欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android自定义View仿IOS选择控件Togglebutton实现

程序员文章站 2022-05-25 08:21:49
...

Android自定义View仿IOS选择控件Togglebutton实现

目前在搞自定义view这一块的东西,将自己手写的很多效果控件将全部展示在博客中,这个是模仿ios的一个控件,虽然有原生的可以直接用了,但是毕竟知道实现更有助于自己写出风格各样的自定义控件。文中会贴出代码,但如果想在实际项目中使用,还需要增加很多逻辑判断以及监听回掉。
原效果图如下:

Android自定义View仿IOS选择控件Togglebutton实现


画图分析

自定义view的绘制最重要的是分析状态以及过程,最好使用笔纸将所需完成的控件画出来,这样可以很清楚的描述出我们的绘制过程,以下是我的绘制理解:

Android自定义View仿IOS选择控件Togglebutton实现

以上即为描绘的几种状态:

原始状态:控件没被选择的状态,圆在左边;
选择点击状态:即点击后发生的状态显示;绿色的圆会往右移动,蓝色框中的白色区域会缩小,选中状态的红颜色会出现,圆在最右边时,白色完全消失;
选择完成状态:蓝色框中的白色区域撤底消失,选中状态的颜色一直出现,圆在右边;
取消选择点击状态:蓝色框中的白色区域会增大,圆会一直往左移动,圆到最左边时白色盖住红色;


代码实现

代码很简单,主要是对设计思路的分析

public class Togglebutton extends View {
    private Region regionClip,regionClick;//点击的截取区域
    private Path pathRoundOut,pathCircleOut,pathCircleIn,pathRoundIn_normal,getPathRoundIn_select;//路径
    private Paint paintRoundOut,paintRoundInNormal,paintRoundInSelect,paintCircleIn,paintCircleOut;//画笔
    private float varySet;//动画的变化值
    private float roundOutWidth=120f,roundOutHeight=60f,circleRadio=28f;//控件的参数
    private int mHeight,mWidth;//画布的宽高
    private boolean choice=false,inner=false;//用来判断事件的句柄
    private ValueAnimator animatorOpen,animatorClose;//动画
    private Matrix matrix;//矩阵
    private float[] dst=new float[2];//当前点击的点
    public Togglebutton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initPaint();
        initValueAnimator();
        matrix=new Matrix();
    }


    /**
     * 初始化画笔
     */
    private void initPaint() {
        paintCircleIn=new Paint();
        paintCircleIn.setStyle(Paint.Style.FILL);
        paintCircleIn.setColor(Color.WHITE);
        paintCircleIn.setAntiAlias(true);

        paintCircleOut=new Paint();
        paintCircleOut.setAntiAlias(true);
        paintCircleOut.setStyle(Paint.Style.STROKE);
        paintCircleOut.setStrokeWidth(1);
        paintCircleOut.setColor(Color.parseColor("#8a8a8a"));

        paintRoundOut=new Paint();
        paintRoundOut.setColor(Color.parseColor("#8a8a8a"));
        paintRoundOut.setAntiAlias(true);
        paintCircleOut.setStyle(Paint.Style.STROKE);
        paintCircleOut.setAntiAlias(true);
        paintCircleOut.setStrokeWidth(1);

        paintRoundInNormal=new Paint();
        paintRoundInNormal.setAntiAlias(true);
        paintRoundInNormal.setStyle(Paint.Style.FILL);
        paintRoundInNormal.setColor(Color.WHITE);

        paintRoundInSelect=new Paint();
        paintRoundInSelect.setStyle(Paint.Style.FILL);
        paintRoundInSelect.setAntiAlias(true);
        paintRoundInSelect.setColor(Color.BLUE);
    }

    /**
     * 初始化路径
     */
    private void initPath() {
        pathCircleIn=new Path();
        pathCircleOut=new Path();
        pathRoundOut=new Path();
        pathRoundIn_normal=new Path();
        getPathRoundIn_select=new Path();
        pathRoundOut.addRoundRect(new RectF(-roundOutWidth/2,-roundOutHeight/2,roundOutWidth/2,roundOutHeight/2),circleRadio+1,circleRadio+1, Path.Direction.CW);
        pathRoundIn_normal.addRoundRect(new RectF(-roundOutWidth / 2 + varySet, -roundOutHeight / 2 + varySet / 2, roundOutWidth / 2 - varySet, roundOutHeight / 2 - varySet / 2), circleRadio, circleRadio, Path.Direction.CW);
        pathCircleIn.addCircle(-roundOutWidth/4+varySet,0,circleRadio, Path.Direction.CW);
        pathCircleOut.addCircle(-roundOutWidth/4+varySet,0,circleRadio+1, Path.Direction.CW);
        getPathRoundIn_select.addRoundRect(new RectF(-roundOutWidth/2,-roundOutHeight/2,roundOutWidth/2,roundOutHeight/2),circleRadio,circleRadio, Path.Direction.CW);
        regionClick=new Region();
        regionClick.setPath(pathRoundOut,regionClip);
    }

    /**
     * 初始化动画
     */
    private void initValueAnimator() {
        animatorOpen = ValueAnimator.ofFloat(0,roundOutWidth/2);
        animatorOpen.setRepeatCount(0);
        animatorOpen.setDuration(500);
        animatorOpen.setInterpolator(new LinearInterpolator());
        animatorOpen.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                varySet= (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        animatorClose = ValueAnimator.ofFloat(roundOutWidth/2,0);
        animatorClose.setRepeatCount(0);
        animatorClose.setDuration(500);
        animatorClose.setInterpolator(new LinearInterpolator());
        animatorClose.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                varySet= (float) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mHeight=h;
        mWidth=w;
        //获取手势的剪裁区域
        regionClip=new Region(-mWidth,-mHeight,mWidth,mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画布平移
        canvas.translate(mWidth/2,mHeight/2);
        initPath();
        matrix.reset();
        if(matrix.isIdentity()){
            //由于画布平移了,矩阵要相应变换,对区域的判断坐标会出问题
            canvas.getMatrix().invert(matrix);
        }
        drawPath(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                dst[0]=event.getRawX();
                dst[1]=event.getRawY();
                matrix.mapPoints(dst);
                //判断手势是否在画的圆角区域内
                inner=regionClick.contains((int)dst[0],(int) dst[1]);
                break;
            case MotionEvent.ACTION_UP:
                dst[0]=event.getRawX();
                dst[1]=event.getRawY();
                matrix.mapPoints(dst);
                //判断手势是否离开
                if(inner&&regionClick.contains((int)dst[0],(int) dst[1])){
                    if(animatorOpen.isRunning()){
                        animatorOpen.cancel();
                    }
                    if (animatorClose.isRunning()){
                        animatorClose.cancel();
                    }
                    choice=!choice;
                    if(choice){
                        animatorOpen.start();
                    }else {
                        animatorClose.start();
                    }
                }

                break;
            default:break;
        }
        return true;
    }

    /**
     * 画
     * @param canvas
     */
    private void drawPath(Canvas canvas) {
        if(choice){
            canvas.drawPath(pathRoundOut,paintRoundInSelect);
        }else {
            canvas.drawPath(pathRoundOut,paintRoundOut);
        }
        canvas.drawPath(getPathRoundIn_select,paintRoundInSelect);
        canvas.drawPath(pathRoundIn_normal,paintRoundInNormal);
        canvas.drawPath(pathCircleOut,paintCircleOut);
        canvas.drawPath(pathCircleIn,paintCircleIn);
    }
}

效果展示

Android自定义View仿IOS选择控件Togglebutton实现

                                            抠脚来的,不喜勿喷