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

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

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

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




画图分析

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



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

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


代码实现

代码很简单,主要是对设计思路的分析
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);
    }
}

效果展示



抠脚来的,不喜勿喷

编辑于 2018-04-24 11:35