项目地址:
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; } }