Android 自定义带动画的 CheckBox

项目地址: CheckBox

写一个带动画化效果的CheckBox,先看效果,我觉得这个尺寸是最好看的,画图板画出来的,有点丑啊。。





怎么用

<org.alex.checkbox.CheckBox
        xmlns:CheckBox="http://schemas.android.com/apk/res-auto"
        android:id="@+id/cb"
        android:layout_width="16dp"
        android:layout_height="24dp"
        android:layout_centerVertical="true"
        android:layout_marginBottom="16dp"
        android:layout_marginLeft="22dp"
        android:paddingTop="12dp"
        CheckBox:cb_canAnim="true"
        CheckBox:cb_checkMarkWidth="2dp"
        CheckBox:cb_checkMarkerDuration="200"
        CheckBox:cb_innerCheckedColor="#FFFFFF"
        CheckBox:cb_innerNormalColor="#FFFFFF"
        CheckBox:cb_outBorderRadius="2dp"
        CheckBox:cb_outBorderWidth="1.5dp"/>

核心代码

/**
 * 作者:Alex
 * 时间:2016/9/8 12:57
 * 简述:
 */
public class CheckBox extends View {
    /**
     * 复选框 默认 大小
     */
    private int defaultSize = 40;
    /**
     * 控件的 尺寸
     */
    private int size;
    /**
     * 最外层的圆角矩形
     */
    private RectF outBorderRectF;
    /**
     * 最外层的圆角矩形
     */
    private Paint outBorderPaint;
    /**
     * 最外层 边框的 宽度
     */
    private float outBorderWidth;
    /**
     * 最外层 边框的 颜色
     */
    private int outBorderColor;
    /**
     * 外边框 圆角化 半径
     */
    private float outBorderRadius;
    /**
     * 内置矩形框
     */
    private RectF innerCheckedRectF;
    /**
     * 内置矩形框
     */
    private Paint innerCheckedPaint;
    /**
     * 内置矩形框 颜色
     */
    private int innerCheckedColor;
    //
    /**
     * 内置矩形框
     */
    private RectF innerNormalRectF;
    /**
     * 内置矩形框
     */
    private Paint innerNormalPaint;
    /**
     * 内置矩形框 颜色
     */
    private int innerNormalColor;
    /**
     * 对勾
     */
    private Paint checkMarkPaint;
    /**
     * 对号的4个点的坐标
     */
    private float[] pointArray;
    /**
     * 对勾的宽度
     */
    private float checkMarkWidth;
    /**
     * 对勾的 颜色
     */
    private int checkMarkColor;
    private float checkMarkerProgress;
    /**
     * 选中
     */
    private boolean isChecked;
    /**
     * 使用过渡动画
     */
    private boolean canAnim;
    /**
     * 展示 对勾 需要的时间长度
     */
    private int checkMarkerDuration;
    private ObjectAnimator checkMarkerShowAnimator;
    private ObjectAnimator checkMarkerDismissAnimator;
    private OnCheckChangeListener onCheckChangeListener;
    private static final String KEY_IS_CHECKED = "IS_CHECKED";
    public CheckBox(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(attrs);
    }
    private void initView(AttributeSet attrs) {
        /*外边框*/
        outBorderRectF = new RectF();
        outBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        outBorderPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        outBorderPaint.setColor(outBorderColor);
        outBorderPaint.setStrokeWidth(outBorderWidth);
        outBorderPaint.setStyle(Paint.Style.STROKE);
        /*内置 矩形框*/
        innerCheckedRectF = new RectF();
        innerCheckedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        innerCheckedPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        innerCheckedPaint.setColor(innerCheckedColor);
        innerCheckedPaint.setStrokeWidth(outBorderWidth);
        innerCheckedPaint.setStyle(Paint.Style.FILL);
        innerNormalRectF = new RectF();
        innerNormalPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        innerNormalPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        innerNormalPaint.setColor(innerNormalColor);
        innerNormalPaint.setStrokeWidth(outBorderWidth);
        innerNormalPaint.setStyle(Paint.Style.FILL);
        /*对勾*/
        checkMarkPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        checkMarkPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        checkMarkPaint.setColor(checkMarkColor);
        checkMarkPaint.setStrokeWidth(checkMarkWidth);
        checkMarkPaint.setStrokeCap(Paint.Cap.ROUND);
        checkMarkPaint.setStyle(Paint.Style.STROKE);
        pointArray = new float[8];
        checkMarkerProgress = (isChecked) ? 1F : 0F;
        /*动画*/
        checkMarkerShowAnimator = ObjectAnimator.ofFloat(this, "checkMarkerProgress", 0F, 1F);
        checkMarkerShowAnimator.setDuration(checkMarkerDuration);
        checkMarkerShowAnimator.addListener(new MySimpleAnimatorListener("checkMarkerShowAnimator"));
        checkMarkerDismissAnimator = ObjectAnimator.ofFloat(this, "checkMarkerProgress", 1F, 0F);
        checkMarkerDismissAnimator.setDuration(checkMarkerDuration);
        checkMarkerDismissAnimator.addListener(new MySimpleAnimatorListener("checkMarkerDismissAnimator"));
        setOnClickListener(new MyOnClickListener());
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        drawInnerNormalRect(canvas);
        drawInnerCheckedRect(canvas);
        canvas.drawRoundRect(outBorderRectF, outBorderRadius, outBorderRadius, outBorderPaint);
        drawCheckMarker(canvas);
    }
    /**
     * 画 内置矩形
     */
    private void drawInnerNormalRect(Canvas canvas) {
        float width = outBorderWidth * 0.5F;
        float checkMarkerProgress = this.checkMarkerProgress;
        innerNormalRectF.left = size * 0.5F * (checkMarkerProgress) + width;
        innerNormalRectF.right = size * (1 - checkMarkerProgress) - width;
        innerNormalRectF.top = size * 0.5F * (checkMarkerProgress) + width;
        innerNormalRectF.bottom = size * (1 - checkMarkerProgress) - width;
        canvas.drawRoundRect(innerNormalRectF, outBorderRadius, outBorderRadius, innerNormalPaint);
    }
    /**
     * 画 内置矩形
     */
    private void drawInnerCheckedRect(Canvas canvas) {
        /*内置矩形*/
        float width = outBorderWidth * 0.5F;
        float checkMarkerProgress = this.checkMarkerProgress;
        if (isChecked) {
            //checkMarkerProgress += 0.5;
        }
        if (checkMarkerProgress >= 1) {
            checkMarkerProgress = 1F;
        }
        innerCheckedRectF.left = size * 0.5F * (1 - checkMarkerProgress) + width;
        innerCheckedRectF.right = size * 0.5F * (1 + checkMarkerProgress) - width;
        innerCheckedRectF.top = size * 0.5F * (1 - checkMarkerProgress) + width;
        innerCheckedRectF.bottom = size * 0.5F * (1 + checkMarkerProgress) - width;
        canvas.drawRoundRect(innerCheckedRectF, outBorderRadius, outBorderRadius, innerCheckedPaint);
    }
    /**
     * 画 对勾
     */
    private void drawCheckMarker(Canvas canvas) {
        if (checkMarkerProgress < 1 / 2f) {
            float x = pointArray[0] + (pointArray[2] - pointArray[0]) * checkMarkerProgress;
            float y = pointArray[1] + (pointArray[3] - pointArray[1]) * checkMarkerProgress;
            canvas.drawLine(pointArray[0], pointArray[1], x, y, checkMarkPaint);
        } else {
            float x = pointArray[4] + (pointArray[6] - pointArray[4]) * checkMarkerProgress;
            float y = pointArray[5] + (pointArray[7] - pointArray[5]) * checkMarkerProgress;
            canvas.drawLine(pointArray[0], pointArray[1], pointArray[2], pointArray[3], checkMarkPaint);
            canvas.drawLine(pointArray[4], pointArray[5], x, y, checkMarkPaint);
        }
    }
    private final class MySimpleAnimatorListener extends SimpleAnimatorListener {
        private String type;
        public MySimpleAnimatorListener(String type) {
            this.type = type;
        }
        @Override
        public void onAnimationStart(Animator animation) {
            super.onAnimationStart(animation);
            if ("checkMarkerShowAnimator".equals(type)) {
                isChecked = true;
            } else if ("checkMarkerDismissAnimator".equals(type)) {
                isChecked = false;
            }
        }
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            if ("checkMarkerShowAnimator".equals(type)) {
                isChecked(true);
            } else if ("checkMarkerDismissAnimator".equals(type)) {
                isChecked(false);
            }
        }
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
            width = height = (int) Math.min(dp2px(defaultSize) - params.leftMargin - params.rightMargin, dp2px(defaultSize) - params.bottomMargin - params.topMargin);
        }
        int size = Math.min(width, height);
        setMeasuredDimension(size, size);
        this.size = size;
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        float halfOutBorderWidth = outBorderWidth * 0.5F;
        outBorderRectF.left = 0 + halfOutBorderWidth;
        outBorderRectF.right = size - halfOutBorderWidth;
        outBorderRectF.top = 0 + halfOutBorderWidth;
        outBorderRectF.bottom = size - halfOutBorderWidth;
        /*对号左边细线  起点 - x */
        pointArray[0] = 121 / 600F * size;
        /*对号左边线  起点 - y */
        pointArray[1] = 309 / 600F * size;
        /*对号左边细线 终点 - x */
        pointArray[2] = 241 / 600F * size;
        /*对号左边细线 终点 - y */
        pointArray[3] = 408 / 600F * size;
        /*对号右边细线  起点 - x */
        pointArray[4] = pointArray[2];
        /*对号右边细线  起点 - y */
        pointArray[5] = pointArray[3];
        /*对号右边细线  终点 - x */
        pointArray[6] = 476 / 600F * size;
        /*对号右边细线  终点 - y */
        pointArray[7] = 181 / 600F * size;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值