Android 开发 ToggleButton 滑动开关按钮

滑动开关按钮实现
本文介绍了一种自定义滑动开关按钮的实现方法,通过XML布局文件定义UI,并使用Java创建View类,实现了按钮的开合状态切换及触摸拖拽功能。

滑动开关按钮的实现

自定义layout布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.xykj.xtogglebutton.MainActivity">

    <com.xykj.view.XToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="50dp" />
    <com.xykj.view.XToggleButton
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:layout_marginTop="10dp"/>
</LinearLayout>
新建View类
public class XToggleButton extends View {
    /**
     * 提供两种构造
     *
     * @param context
     */
    public XToggleButton(Context context) {
        super(context);
        init();
    }

    public XToggleButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    //视图的宽度
    private int width;

    //背景部分左右圆的半径
    private int radius;
    //左边圆的圆心
    private Point centerLeft;
    //右边圆的圆心
    private Point centerRight;
    //中间的矩形
    private Rect bgRect;

    //画笔
    private Paint paint;
    //是否是开
    private boolean isOpen;
    //拖动的圆的圆心
    private Point thumbCenter;
    //拖动的圆的半径
    private int thumbRadius;
    //是否是拖动中
    private boolean isDragging;

    //文本的起始点
    private Point leftTextPoint;
    private Point rightTextPoint;
    //开关的模式
    private String openText = "开";
    private String closeText = "关";

    //定义开关的背景颜色
    private static final int openColor = 0xFF303F9F;
    private static final int closeColor = 0xff666666;

    //初始化
    private void init() {
        centerLeft = new Point();
        centerRight = new Point();
        thumbCenter = new Point();
        leftTextPoint = new Point();
        rightTextPoint = new Point();
        bgRect = new Rect();
        paint = new Paint();
        paint.setAntiAlias(true);
    }

    //矩形左边的文本
    private Rect textLeftRect = new Rect();
    //矩形右边的文本
    private Rect textRightRect = new Rect();

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //显示的宽度
        width = getDefaultSize(120, widthMeasureSpec);
        //显示的高度
        int h = getDefaultSize(60, heightMeasureSpec);
        //画的内容高度
        int height = h;
        if (h > width / 2) {
            height = width / 2;
        }
        //左右圆的半径
        radius = height / 2;
        centerLeft.set(radius, h / 2);
        centerRight.set(width - radius, h / 2);
        //设置两个圆中间的矩形(根据背景的两个圆的圆心来控制)
        bgRect.set(centerLeft.x, centerLeft.y - radius, centerRight.x, centerLeft.y + radius);
        //判断开关状态
        if (isOpen) {
            thumbCenter.set(centerRight.x, centerRight.y);
        } else {
            //默认先将拖块放左边
            thumbCenter.set(centerLeft.x, centerLeft.y);
        }
        //拖块的半径比背景圆的半径减少5个单位
        thumbRadius = radius - 5;
        //文本大小
        paint.setTextSize(thumbRadius);
        paint.getTextBounds(openText, 0, openText.length(), textLeftRect);
        paint.getTextBounds(closeText, 0, closeText.length(), textRightRect);
        //计算左边文本的起始点,进行文本的定位
        leftTextPoint.set(centerLeft.x - textLeftRect.centerX(), centerLeft.y - textLeftRect.centerY());
        rightTextPoint.set(centerRight.x - textRightRect.centerX(), centerRight.y - textRightRect.centerY());
        setMeasuredDimension(width, h);
    }

    public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);

        switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.AT_MOST:
                result = size;
                break;
            case MeasureSpec.EXACTLY:
                int specSize = MeasureSpec.getSize(measureSpec);
                result = specSize;
                break;
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画背景(判断是否是已开启状态,是就显示开的背景,若是关闭状态就显示关闭的背景颜色)
        paint.setColor(isOpen ? openColor : closeColor);
        //左圆右圆
        canvas.drawCircle(centerLeft.x, centerLeft.y, radius, paint);
        canvas.drawCircle(centerRight.x, centerRight.y, radius, paint);
        //画中间矩形
        canvas.drawRect(bgRect, paint);

        //画拖动中的背景
        if (isDragging) {
            //如果是打开状态下,拖块在右边
            if (isOpen) {
                //要被盖住的文本
                drawText(canvas, true);
                //从右边开始拖动,画出内圆所画的轨迹(控制轨迹的边界,不能溢出)
                paint.setColor(closeColor);
                canvas.drawCircle(centerRight.x, centerRight.y, thumbRadius, paint);
                canvas.drawRect(thumbCenter.x, thumbCenter.y - thumbRadius, centerRight.x, thumbCenter.y + thumbRadius, paint);
            } else {
                //要被盖住的文本
                drawText(canvas, false);
                canvas.drawText(openText, leftTextPoint.x, leftTextPoint.y, paint);
                //从左边开始拖动,画出内圆所画的轨迹(控制轨迹的边界,不能溢出)
                paint.setColor(openColor);
                canvas.drawCircle(centerLeft.x, centerLeft.y, thumbRadius, paint);
                canvas.drawRect(centerLeft.x, centerLeft.y - thumbRadius, thumbCenter.x, centerLeft.y + thumbRadius, paint);
            }
            //要显示的文本
            drawText(canvas, !isOpen);
        } else {
            drawText(canvas, isOpen);
        }
        //画拖块
        paint.setColor(0xFF3F51B5);
        canvas.drawCircle(thumbCenter.x, thumbCenter.y, thumbRadius, paint);
    }

    //判断开关是否为打开状态,把文本文字定位到开关上
    private void drawText(Canvas canvas, boolean open) {
        if (open) {
            paint.setColor(Color.WHITE);
            canvas.drawText(openText, leftTextPoint.x, leftTextPoint.y, paint);
        } else {
            paint.setColor(Color.BLACK);
            canvas.drawText(closeText, rightTextPoint.x, rightTextPoint.y, paint);
        }
    }

    //上一个拖动的x坐标
    private int lastX;
    //记录按下的时间
    private long downTime;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                isDragging = true;
                lastX = (int) event.getX();
                downTime = System.currentTimeMillis();
                break;
            case MotionEvent.ACTION_MOVE:
                if (isDragging) {
                    //当前拖动的位置
                    int currentX = (int) event.getX();
                    //计算间距
                    int x1 = currentX - lastX;
                    //计算新的中心点x
                    int nX = thumbCenter.x + x1;
                    if (nX < centerLeft.x) {
                        nX = centerLeft.x;
                    } else if (nX > centerRight.x) {
                        nX = centerRight.x;
                    }
                    //改变圆心
                    thumbCenter.x = nX;
                    //让下一个点基于当前点去偏移
                    lastX = currentX;
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                long currentTime = System.currentTimeMillis();
                long t = currentTime - downTime;
                if (!isOpen) {
                    if (t <= 200) {
                        //打开
                        open();
                    } else if (isDragging) {
                        //检测拖动是否超过一半
                        if (thumbCenter.x > width / 2) {
                            //打开
                            open();
                        } else {
                            thumbCenter.x = centerLeft.x;
                        }
                    }
                } else {
                    if (t <= 200) {
                        close();
                    } else if (isDragging) {
                        //检测有没有拖过一半
                        if (thumbCenter.x < width / 2) {
                            //关闭
                            close();
                        } else {
                            thumbCenter.x = centerRight.x;
                        }
                    }
                }
                isDragging = false;
                invalidate();
                break;
        }
        return true;
    }

    private void open() {
        thumbCenter.x = centerRight.x;
        isOpen = true;
    }

    private void close() {
        thumbCenter.x = centerLeft.x;
        isOpen = false;
    }
}
效果如下图:

ToggleButton

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值