自定义view————开关button

陷入自定义view的坑越陷越深,励志要把自定义view撸给遍,今天给大家介绍一下自定义view————开关button,这个在很多app中都能用的,废话不多说,先来给动图。

效果图

分析一下上面的效果:四个状态:关闭状态、关闭->打开过程、打开状态、打开->关闭过程,结合ValueAnimator动效实现这个过程

关闭状态

绘制一个圆角矩形(drawRoundRect()方法),再画一个圆(drawCircle()),默认关闭就画好了

    RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
    //先画背景
    canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

    //再画圆
    canvas.drawCircle(closecenterX, closecenterY, circleRadius, circlePaint);复制代码

打开状态

绘制了关闭状态,再绘制打开状态,,最后绘制关闭->打开状态,打开->关闭状态,其实这里和关闭状态类似的,只是画圆的x、y的位置不一样而已


    RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
    //先画背景
    canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

    RectF rectFAnimation = new RectF(padding, padding, o2cright, o2cbottom);
    //先画背景
    canvas.drawRoundRect(rectFAnimation, backgroundRadius, backgroundRadius, openPaint);

    //再画圆
    canvas.drawCircle(o2ccenterX, o2ccenterY, circleRadius, circlePaint);复制代码

关闭->打开状态

ValueAnimator动效中的addUpdateListener()的回调通过valueAnimator.getAnimatedValue();来重新绘制过程,计算圆在状态变化时的x,y及其圆角矩形的right,bottom值来动态改变然后重新绘制。

记录动态的变化值


 close2OpengvalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator valueAnimator) {
                 mclose2OpenAnimatorValue = (float) valueAnimator.getAnimatedValue();
                 //圆在状态变化时的x,y
                 c2ocenterX = closecenterX + closeOpenX * mclose2OpenAnimatorValue;
                 c2ocenterY = backgroundRadius + padding;
                 //背景的右下标=关闭状态的位置(2*backgroundRadius+padding)+差值*变化
                 c2oright = 2 * backgroundRadius + padding + closeOpenRight * mclose2OpenAnimatorValue;
                 //背景的底下标=关闭状态的位置(2*backgroundRadius+padding)+差值*变化
                 c2obottom = 2 * backgroundRadius + padding + closeOpenBottom * mclose2OpenAnimatorValue;
                 invalidate();
             }
         });
         close2OpengvalueAnimator.addListener(new Animator.AnimatorListener() {
             @Override
             public void onAnimationStart(Animator animator) {

             }

             @Override
             public void onAnimationEnd(Animator animator) {
                 setOpen();
                 invalidate();
             }

             @Override
             public void onAnimationCancel(Animator animator) {

             }

             @Override
             public void onAnimationRepeat(Animator animator) {

             }
         });复制代码

根据变化值重新绘制

     RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
     //先画背景
     canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

     RectF rectFAnimation = new RectF(padding, padding, c2oright, c2obottom);
     //先画背景
     canvas.drawRoundRect(rectFAnimation, backgroundRadius, backgroundRadius, openPaint);

     //再画圆
     canvas.drawCircle(c2ocenterX, c2ocenterY, circleRadius, circlePaint);复制代码

打开->关闭状态

这个动画状态和上面的动画状态同理

记录变化值


openg2ClosevalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mopeng2CloseAnimatorValue = (float) valueAnimator.getAnimatedValue();

                //圆在状态变化时的x,y
                o2ccenterX = closecenterX+closeOpenX * mopeng2CloseAnimatorValue;
                o2ccenterY = backgroundRadius + padding;
                //背景的右下标=关闭状态的位置(2*backgroundRadius+padding)+差值*变化
                o2cright = 2 * backgroundRadius + padding + closeOpenRight * mopeng2CloseAnimatorValue;
                //背景的底下标=关闭状态的位置(2*backgroundRadius+padding)+差值*变化
                o2cbottom = 2 * backgroundRadius + padding + closeOpenBottom * mopeng2CloseAnimatorValue;
                invalidate();

            }
        });
        openg2ClosevalueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                setClose();
                invalidate();
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });复制代码

根据变化值重新绘制

            RectF rectF = new RectF(padding, padding, mwidth - padding, mheight - padding);
            //先画背景
            canvas.drawRoundRect(rectF, backgroundRadius, backgroundRadius, closePaint);

            RectF rectFAnimation = new RectF(padding, padding, o2cright, o2cbottom);
            //先画背景
            canvas.drawRoundRect(rectFAnimation, backgroundRadius, backgroundRadius, openPaint);

            //再画圆
            canvas.drawCircle(o2ccenterX, o2ccenterY, circleRadius, circlePaint);复制代码

上面的四种状态介绍完毕了,大致功能就实现了,接下来介绍一些属性的设置、四种状态设置的方法、点击事件等

四种状态的设置

    /***
     * 关闭
     */
    private void setClose() {
        mcurrentState = State.CLOSE;
        invalidate();
    }

    /***
     * 打开
     */
    private void setOpen() {
        mcurrentState = State.OPEN;
        invalidate();
    }

    /***
     * 关闭到打开
     */
    private void setClose2Open() {
        mcurrentState = State.CLOSE2OPEN;
        openg2ClosevalueAnimator.removeAllUpdateListeners();
        addCloseToOpenAnimator();
        close2OpengvalueAnimator.start();
    }

    /***
     * 打开到关闭
     */
    private void setOpen2Close() {
        mcurrentState = State.OPEN2CLOSE;
        close2OpengvalueAnimator.removeAllUpdateListeners();
        addOpenToCloseAnimator();
        openg2ClosevalueAnimator.start();
    }复制代码

点击事件执行打开关闭

    /***
     * 控件点击执行该方法 改变状态
     */
    public void onclick(){
        if(mcurrentState==State.CLOSE){
            setClose2Open();
        }else if(mcurrentState==State.OPEN){
            setOpen2Close();
        }
    }复制代码

属性的设置

xml设置

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SwitchButton">
        <attr name="backgroudColor" format="color"/>
        <attr name="closeColor" format="color"/>
        <attr name="openColor" format="color"/>
        <attr name="circleColor" format="color"/>
        <attr name="animatorTime" format="integer"/>
        <attr name="padding" format="integer"/>
    </declare-styleable>
</resources>复制代码
    private void initTypeArray(Context context, AttributeSet attrs) {
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.SwitchButton);
        backgroudColor=typedArray.getColor(R.styleable.SwitchButton_backgroudColor,Color.WHITE);
        closeColor=typedArray.getColor(R.styleable.SwitchButton_closeColor,Color.GRAY);
        openColor=typedArray.getColor(R.styleable.SwitchButton_openColor,Color.GREEN);
        circleColor=typedArray.getColor(R.styleable.SwitchButton_circleColor,Color.WHITE);
        padding=typedArray.getInteger(R.styleable.SwitchButton_padding,1);
        animatorTime=typedArray.getInteger(R.styleable.SwitchButton_animatorTime,500);
        typedArray.recycle();
    }复制代码

xml中设置

    <com.switchbutton.SwitchButton
        android:id="@+id/btn1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="20dp"
        app:closeColor="@color/colorAccent"
        app:openColor="@android:color/holo_green_light"
        app:padding="6"
        app:animatorTime="1000"
        />复制代码
代码设置


    /**
     * 设置背景颜色
     * @param backgroudColor
     */
    public void setBackgroudColor(int backgroudColor) {
        this.backgroudColor = backgroudColor;
    }

    /**
     * 关闭状态颜色
     * @param closeColor
     */
    public void setCloseColor(int closeColor) {
        this.closeColor = closeColor;
        closePaint.setColor(closeColor);
    }

    /**
     * 打开状态颜色
     * @param openColor
     */
    public void setOpenColor(int openColor) {
        this.openColor = openColor;
        openPaint.setColor(openColor);
    }

    /**
     * 圆的颜色
     * @param circleColor
     */
    public void setCircleColor(int circleColor) {
        this.circleColor = circleColor;
        circlePaint.setColor(circleColor);
    }

    /**
     * 间距
     * @param padding
     */
    public void setPadding(int padding) {
        this.padding = padding;
    }

    /**
     * 动画时间
     * @param animatorTime
     */
    public void setAnimatorTime(int animatorTime) {
        this.animatorTime = animatorTime;
    }复制代码

考虑实践应用中,需要获取相关状态,上传至服务器/根据状态设置相关设置等

    /**
     * 获取当前的状态 用于使用时的需求
     * @return
     */
    public State getMcurrentState() {
        return mcurrentState;
    }复制代码

其他方法也可以实现,根据自己的需求去做相应的更改

SwitchButton GitHub demo地址

个人博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值