ColorPickerDialog 自定义颜色选择器的实现

最近在写的项目Awosome-Campus 中需要用到颜色选择器,用于更改主题,自己写了个。另外我想将它用于之前的项目闲暇(Leisure)中,干脆就将它单独分离出来了。代码规范,添加了详细注释。后来又想想为什么不尝试将它打包发布,说干就干。过程曲折,除夕前夜搞到三点多都没有弄好,第二天(过年)下午四五点才算发布成功。不过这篇博文不是讲怎样打包发布,而是主要介绍它的实现。
我是照着酷安的颜色选择器做的,使用了下,感觉用Dialog比较方便,只要实现中间的View,其他的逻辑就不用管了。这个自定义View支持自由添加颜色,自由选择颜色以及排版。最终做出的效果:

实现思路

  1. 将它进行分解,首先实现单个的圆点:
    1) 继承View,绘制圆形,同时根据当前原点是否被选中决定是否绘制”对勾”
    2) 圆形绘制有现成的方法,对勾根据圆形半径计算,固定三个点连线即可。这里需要注意的是”对勾”的颜色,默认为 白色,如果原点本身颜色偏白(rgb值接近0) 就绘制黑色的”勾”。
    3) 然后是布局,根布局是垂直方向的线性布局,然后以行为单位一行一行地添加到根布局中。这里的”行”是一个水平
    方向的线性布局,每一行再添加规定数量的”圆点”,圆点之间加margin【这里实现有点技巧】

4) 添加一个接口,用于对点击进行响应,这里需要获取选中的颜色值。实现就是经常用的listener了(观察者模式? ),
View本身有个onClickListener,实现它,在onClick中调用我这个接口即可。同时在选中新的颜色的时候也要将之
前“被选中的圆点”置为非选中状态。
5)最后封装成一个View add 到 AlterDialog中就可以了,AlterDialog的宽高也需要根据圆点数量什么的计算一下。

放下圆点(ColorButton)的代码,其他代码见文末GitHub:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/***
* Created by MummyDing on 16-2-4.
* GitHub: https://github.com/MummyDing
* Blog: http://blog.csdn.net/mummyding
*/
public class ColorButton extends View {
private Context mContext;
/**
* color of the ColorButton,default RED.
*/
private int mColor = Color.RED;
/**
* radius of the ColorButton
*/
private int mRadius;
private boolean isChecked = false;
private Paint mPaint;
/**
* paddingHorizontal is relative to the "circle" inside ColorButton (Horizontal)
*/
private int paddingHorizontal;
/**
* paddingVertical is relative to the "circle" inside ColorButton (Vertical)
*/
private int paddingVertical;
/**
* real width of ColorButton (including paddingHorizontal)
* width = 2*(mRadius + paddingHorizontal)
*/
private int width;
/**
* real height of ColorButton (including paddingVertical)
* height = 2*(mRadius + paddingVertical)
*/
private int height;
/**
* set size to defaultWidth if user has not specified
* unit: dip
*/
private int defaultWidth = 30;
public ColorButton(Context context, int color) {
super(context);
mContext = context;
mColor = color;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(5);
defaultWidth = DisplayUtil.dip2px(mContext,defaultWidth);
}
public ColorButton(Context context) {
this(context,Color.RED);
}
public ColorButton(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(5);
defaultWidth = DisplayUtil.dip2px(mContext,defaultWidth);
}
public ColorButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(5);
defaultWidth = DisplayUtil.dip2px(mContext,defaultWidth);
}
/**
* ColorButton is not support self-define padding
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
setMeasuredDimension(defaultWidth,defaultWidth);
}else if(widthMode == MeasureSpec.AT_MOST){
setMeasuredDimension(defaultWidth,heightSize);
}else if(heightMode == MeasureSpec.AT_MOST){
setMeasuredDimension(widthSize,defaultWidth);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = getWidth();
height = getHeight();
mRadius = Math.min(width,height)/2;
paddingHorizontal = (width - mRadius*2)/2;
paddingVertical = (height - mRadius*2)/2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCircle(canvas);
if(isChecked()){
drawCheck(canvas);
}
}
private void drawCircle(Canvas canvas){
mPaint.setColor(mColor);
canvas.drawCircle(paddingHorizontal + width/2,paddingVertical + height/2,mRadius,mPaint);
}
private void drawCheck(Canvas canvas){
if(-40 <mColor && mColor< 40){
mPaint.setColor(Color.BLACK);
}else {
mPaint.setColor(Color.WHITE);
}
Point p1 = new Point(paddingHorizontal + (int)(0.3 * (double) mRadius),paddingVertical + mRadius);
Point p2 = new Point(paddingHorizontal + (int)(0.8 * (double) mRadius),paddingVertical + (int)(1.4 * (double) mRadius));
Point p3 = new Point(paddingHorizontal + (int)(1.4 * (double)mRadius),paddingVertical +(int)(0.4 * (double) mRadius));
canvas.drawLine(p1.x,p1.y,p2.x,p2.y,mPaint);
canvas.drawLine(p2.x,p2.y,p3.x,p3.y,mPaint);
}
public boolean isChecked() {
return isChecked;
}
public void setChecked(boolean checked) {
isChecked = checked;
invalidate();
}
public int getmColor() {
return mColor;
}
}

GitHub项目地址:https://github.com/MummyDing/ColorPickerDialog
其他完整开源项目: https://github.com/MummyDing/Leisure

Contents
|