自定义View——ToggleButton

ToggleButton

效果:

这里写图片描述

之前项目用到toggleButton,但是用的是别人的开源控件。。。现在比以前技术好一点,就想说自定义一个。。。结果发现通过属性动画很简单的就把效果实现了。。。因为难度不高,就不分开讲解,注释也比较清楚。。下面是具体代码:

public class ToggleButton extends View implements View.OnClickListener{
    /*
        打开时的画笔
     */
    private Paint mOnPaint;
    /*
        关闭时的画笔
     */
    private Paint mOffPaint;
    /*
        游标的画笔
     */
    private Paint mFrontPaint;
    /*
        是否打开的布尔值
     */
    private boolean isCheck = false;
    /*
        因为在onDraw里面最好不要实例化对象,所以定义为成员变量
        rectBack:背景框的矩形
        rectFront:前景框的矩形
     */
    private RectF rectBack;
    private RectF rectFront;
    /*
        关闭时的颜色
     */
    private int mOffColor = 0Xffcccad2;
    /*
        打开时的颜色
     */
    private int mOnColor = 0xff01c78f;
    /*
        游标的颜色
     */
    private int mCircleColor = 0xfff5f5f5;
    /*
        游标和边界的间距
     */
    private float circlePadding;
    /*
        游标中心X坐标
     */
    private float start;

    public ToggleButton(Context context) {
        this(context, null, 0);
    }

    public ToggleButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mOnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mOffPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mFrontPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        rectBack = new RectF();
        rectFront = new RectF();

        circlePadding = dpToPx(2);

        setOnClickListener(this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //默认为Exactly
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = (int) (width * (5/9f));
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //初始化start
        start = isCheck ? getWidth() - (getHeight() / 2f) : getHeight()/2f;
    }

    public void setCheck(boolean isCheck) {
        this.isCheck = isCheck;
    }

    public void setOffColor(int mOffColor) {
        this.mOffColor = mOffColor;
    }

    public void setOnColor(int mOnColor) {
        this.mOnColor = mOnColor;
    }

    public void setCircleColor(int mCircleColor) {
        this.mCircleColor = mCircleColor;
    }

    public void setCirclePadding(int dp) {
        this.circlePadding = dpToPx(dp);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //设置画笔颜色
        mOnPaint.setColor(mOnColor);
        mOffPaint.setColor(mOffColor);
        mFrontPaint.setColor(mCircleColor);

        float backStartX = getHeight()/2f;

        //画背景的圆角矩形
        rectBack.set(0, 0, getWidth(), getHeight());
        canvas.drawRoundRect(rectBack, backStartX, backStartX, mOffPaint);

        //画前景的圆角矩形,当处于关闭状态时不画
        if (start!=backStartX) {
            rectFront.set(0, 0, start + backStartX, getHeight());
            canvas.drawRoundRect(rectFront, backStartX, backStartX, mOnPaint);
        }

        //画游标
        canvas.drawCircle(start, getHeight() / 2f, getHeight() / 2f - circlePadding, mFrontPaint);
    }

    /*
        打开时调用动画
     */
    private void checkOn(){
        ValueAnimator animator = ValueAnimator.ofFloat(getHeight() / 2f, getWidth() - (getHeight() / 2f));
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                start = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (onCheckedListener!=null) {
                    onCheckedListener.checkFinish(true);
                }
            }
        });
        animator.setDuration(200);
        animator.start();
    }

    /*
        关闭时调用动画
     */
    private void checkOff(){
        ValueAnimator animator = ValueAnimator.ofFloat(getWidth() - (getHeight() / 2f), getHeight() / 2f);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                start = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (onCheckedListener!=null) {
                    onCheckedListener.checkFinish(false);
                }
            }
        });
        animator.setDuration(200);
        animator.start();
    }

    /*
        将dp转换为px
     */
    private float dpToPx(int dp){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
    }

    private OnCheckedListener onCheckedListener;

    /*
        设置接口
     */
    public void setOnCheckedListener(OnCheckedListener checkedListener) {
        this.onCheckedListener = checkedListener;
    }

    /*
        定义一个接口,分别是打开时和关闭时调用
     */
    public interface OnCheckedListener{
        void checkFinish(boolean isCheck);
    }

    /*
        监听点击
     */
    @Override
    public void onClick(View v) {
        if (!isCheck) {
            checkOn();
        } else {
            checkOff();
        }
        isCheck = !isCheck;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值