![]() 如何制作一个上图所示的material design风格的Checkbox观察上图初步确定我们需要做的的包括 边框的绘制 checkbox背景色的绘制 中心的选中图标的绘制 然后加上动画效果,下面开始动手编写 1.定义我需要的画布及画笔//绘制背景画笔 private Paint bitmapPaint; //擦除背景的橡皮擦 private Paint bitmapEraser; //绘制选中图标的画笔 private Paint checkEraser; //绘制边框的画笔 private Paint borderPaint; //背景画布 private Canvas bitmapCanvas; //绘制选中图标的画布 private Canvas checkCanvas; 从图中可以看出从未选中到选中背景色是由外向内逐渐填充,反之是由内向外逐渐擦除。 2.初始化变量//Paint.ANTI_ALIAS_FLAG 表示抗锯齿,为了在执行动画时候不出现你不想看到的东西 bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); bitmapEraser = new Paint(Paint.ANTI_ALIAS_FLAG); bitmapEraser.setColor(0); bitmapEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); checkEraser = new Paint(Paint.ANTI_ALIAS_FLAG); checkEraser.setColor(0); checkEraser.setStyle(Paint.Style.STROKE); checkEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); borderPaint.setStyle(Paint.Style.STROKE); borderPaint.setStrokeWidth(dp(2)); //为了让选中的图标更美观就通过图片的形式添加, checkDrawable = context.getResources().getDrawable(R.mipmap.check); 主要通过setXfermode 为 Mode.CLEAR 来实现一个橡皮擦的功能 这里深入的讲解了这几种模式 有兴趣可以学习 3.添加动画,实现由内向外及由外向内的擦除效果
private void addAnim(boolean isChecked) {
checkAnim = ObjectAnimator.ofFloat(this, "progress", isChecked ? 1.0f : 0.0f);
checkAnim.setDuration(300);
checkAnim.start();
}
private float progress;
public void setProgress(float value) {
if (progress == value) {
return;
}
progress = value;
invalidate();
}
public float getProgress() {
return progress;
}
添加属性动画,我们指定了progress属性就必须去提供相应的 set get 方法,才能对相应属性做修改,通过一个0-1的float类型值 不断改变橡皮擦的绘制半径 来达到动画效果。 4.控件的绘制//获取半径 float rad = getMeasuredWidth() / 2; //绘制边框 borderPaint.setColor(borderColor); canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad - dp(1), borderPaint); //绘制背景 bitmapPaint.setColor(bitmapColor); bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad, bitmapPaint); //根据progress 来更改橡皮擦的绘制半径,来实现正向与反向的绘制 bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad * (1 - progress), bitmapEraser); //根据progress 来更改选中图标的橡皮擦半斤 checkCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad * (1 - progress), checkEraser); 到这里其实就可以运行效果了,但和上图还是有一些差距 ![]()
对比后发现不同之处在于点击后没有回弹的效果,中心的图标显示好像也有些区别 //控制progress 让其前一半时间来执行背景的擦除动画,后一半时间来执行中心图标的擦除动画 float bitmapProgress = progress >= 0.5f ? 1.0f : progress / 0.5f; float checkProgress = progress < 0.5f ? 0.0f : (progress - 0.5f) / 0.5f; //根据progress 来更改橡皮擦的绘制半径,来实现正向与反向的绘制 bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad * (1 - bitmapProgress), bitmapEraser); //根据progress 来更改选中图标的橡皮擦半斤 checkCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad * (1 - checkProgress), checkEraser); 继续添加回弹的效果
//首先来添加回弹的范围,我们定在20%
private final static float BOUNCE_VALUE = 0.2f;
//根据选中状态来得到我们需要的progress
float p = isChecked ? progress : (1.0f - progress);
//让其在我们设定的范围内 改变绘制圆形半径 从100%缩小到80% 再回到100%
if (p < BOUNCE_VALUE) {
rad -= dp(2) * p ;
} else if (p < BOUNCE_VALUE * 2) {
rad -= dp(2) - dp(2) * p;
}
到这里我们就基本完成了上面的效果 5.让它更像一个自定义控件这是一个选择框,就应该有它该有的功能,我们像原生的 Checkbox一样去实现Checkable接口,来提供一下方法 void setChecked(boolean var1); boolean isChecked(); void toggle(); 为了让控件能够在xml视图文件中更好的配置,像下面这样
<com.yourPackageName.CheckBoxSample
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:color_background="#FF00BCD4"
app:color_border="#FFFFFFFF"
app:size="32dp" />
还需要提供我们自己定义的属性 attrs.xml
<declare-styleable name="CheckBox_Sample">
<attr name="size" format="dimension" />
<attr name="color_border" format="color" />
<attr name="color_background" format="color" />
</declare-styleable>
然后在代码中调用即可 TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CheckBox_Sample); size = ta.getDimensionPixelSize(R.styleable.CheckBox_Sample_size, dp(size)); bitmapColor = ta.getColor(R.styleable.CheckBox_Sample_color_background, bitmapColor); borderColor = ta.getColor(R.styleable.CheckBox_Sample_color_border, borderColor); ta.recycle(); 为了让我们的控件只接受我们自己定义的app:size属性 而不受 android:layout_width android:layout_height的影响,可以通过重写onMeasure方法来实现
//MeasureSpec是由大小和模式所组成,我们只改变大小不改变模式,所以获取之前的模式,加入我们指定的大小通过`MeasureSpec.makeMeasureSpec`方法重新创建`MeasureSpec`即可
//这里推荐任玉刚的《开发艺术探索》在view的工作原理章节讲的非常清楚
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int newSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.getMode(Math.min(widthMeasureSpec, heightMeasureSpec)));
super.onMeasure(newSpec, newSpec);
}
到这里就是一个比较完善的自定义控件了 (责任编辑:最模板) |



shopex缤纷商城模板
人气:661
ecshop仿天猫超市2016整站模
人气:1699
亚洲产品外贸ecshop模板
人气:825
仿万家购物网 购物返利网
人气:4560
化妆品模板 ecshop化妆品网
人气:504
京东商城360buy模板|ecshop京
人气:1358