正文  UI设计 > 选择器(Picker) >

Android 颜色选择器(ColorPicker)

1.瀀愀挀欀愀最攀 com.dwood.paintdemo;2.3.椀洀瀀漀爀琀 android.app.Dialog;4.椀洀瀀漀爀琀 android.content.C...

1. package com.dwood.paintdemo; 
2.  
3. import android.app.Dialog; 
4. import android.content.Context; 
5. import android.graphics.Canvas; 
6. import android.graphics.Color; 
7. import android.graphics.LinearGradient; 
8. import android.graphics.Paint; 
9. import android.graphics.RectF; 
10. import android.graphics.Shader; 
11. import android.graphics.SweepGradient; 
12. import android.os.Bundle; 
13. import android.util.Log; 
14. import android.view.MotionEvent; 
15. import android.view.View; 
16. import android.view.WindowManager; 
17.  
18. public class ColorPickerDialog extends Dialog { 
19.     private final boolean debug = true; 
20.     private final String TAG = "ColorPicker"; 
21.      
22.     Context context; 
23.     private String title;//标题 
24.     private int mInitialColor;//初始颜色 
25.     private OnColorChangedListener mListener; 
26.  
27.     /**
28.      * 初始颜色黑色
29.      * @param context
30.      * @param title 对话框标题
31.      * @param listener 回调
32.      */ 
33.     public ColorPickerDialog(Context context, String title,  
34.             OnColorChangedListener listener) { 
35.         this(context, Color.BLACK, title, listener); 
36.     } 
37.      
38.     /**
39.      * 
40.      * @param context
41.      * @param initialColor 初始颜色
42.      * @param title 标题
43.      * @param listener 回调
44.      */ 
45.     public ColorPickerDialog(Context context, int initialColor,  
46.             String title, OnColorChangedListener listener) { 
47.         super(context); 
48.         this.context = context; 
49.         mListener = listener; 
50.         mInitialColor = initialColor; 
51.         this.title = title; 
52.     } 
53.  
54.     @Override 
55.     protected void onCreate(Bundle savedInstanceState) { 
56.         super.onCreate(savedInstanceState); 
57.         WindowManager manager = getWindow().getWindowManager(); 
58.         int height = (int) (manager.getDefaultDisplay().getHeight() * 0.5f); 
59.         int width = (int) (manager.getDefaultDisplay().getWidth() * 0.7f); 
60.         ColorPickerView myView = new ColorPickerView(context, height, width); 
61.         setContentView(myView); 
62.         setTitle(title); 
63.     } 
64.      
65.     private class ColorPickerView extends View { 
66.         private Paint mPaint;//渐变色环画笔 
67.         private Paint mCenterPaint;//中间圆画笔 
68.         private Paint mLinePaint;//分隔线画笔 
69.         private Paint mRectPaint;//渐变方块画笔 
70.          
71.         private Shader rectShader;//渐变方块渐变图像 
72.         private float rectLeft;//渐变方块左x坐标 
73.         private float rectTop;//渐变方块右x坐标 
74.         private float rectRight;//渐变方块上y坐标 
75.         private float rectBottom;//渐变方块下y坐标 
76.          
77.         private final int[] mCircleColors;//渐变色环颜色 
78.         private final int[] mRectColors;//渐变方块颜色 
79.          
80.         private int mHeight;//View高 
81.         private int mWidth;//View宽 
82.         private float r;//色环半径(paint中部) 
83.         private float centerRadius;//中心圆半径 
84.          
85.         private boolean downInCircle = true;//按在渐变环上 
86.         private boolean downInRect;//按在渐变方块上 
87.         private boolean highlightCenter;//高亮 
88.         private boolean highlightCenterLittle;//微亮 
89.          
90.         public ColorPickerView(Context context, int height, int width) { 
91.             super(context); 
92.             this.mHeight = height - 36; 
93.             this.mWidth = width; 
94.             setMinimumHeight(height - 36); 
95.             setMinimumWidth(width); 
96.              
97.             //渐变色环参数 
98.             mCircleColors = new int[] {0xFFFF0000, 0xFFFF00FF, 0xFF0000FF,  
99.                     0xFF00FFFF, 0xFF00FF00,0xFFFFFF00, 0xFFFF0000}; 
100.             Shader s = new SweepGradient(0, 0, mCircleColors, null); 
101.             mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
102.             mPaint.setShader(s); 
103.             mPaint.setStyle(Paint.Style.STROKE); 
104.             mPaint.setStrokeWidth(50); 
105.             r = width / 2 * 0.7f - mPaint.getStrokeWidth() * 0.5f; 
106.              
107.             //中心圆参数 
108.             mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
109.             mCenterPaint.setColor(mInitialColor); 
110.             mCenterPaint.setStrokeWidth(5); 
111.             centerRadius = (r - mPaint.getStrokeWidth() / 2 ) * 0.7f; 
112.              
113.             //边框参数 
114.             mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
115.             mLinePaint.setColor(Color.parseColor("#72A1D1")); 
116.             mLinePaint.setStrokeWidth(4); 
117.              
118.             //黑白渐变参数 
119.             mRectColors = new int[]{0xFF000000, mCenterPaint.getColor(), 0xFFFFFFFF}; 
120.             mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
121.             mRectPaint.setStrokeWidth(5); 
122.             rectLeft = -r - mPaint.getStrokeWidth() * 0.5f; 
123.             rectTop = r + mPaint.getStrokeWidth() * 0.5f +  
124.                     mLinePaint.getStrokeMiter() * 0.5f + 15; 
125.             rectRight = r + mPaint.getStrokeWidth() * 0.5f; 
126.             rectBottom = rectTop + 50; 
127.         } 
128.  
129.         @Override 
130.         protected void onDraw(Canvas canvas) { 
131.             //移动中心 
132.             canvas.translate(mWidth / 2, mHeight / 2 - 50); 
133.             //画中心圆 
134.             canvas.drawCircle(0, 0, centerRadius,  mCenterPaint); 
135.             //是否显示中心圆外的小圆环 
136.             if (highlightCenter || highlightCenterLittle) { 
137.                 int c = mCenterPaint.getColor(); 
138.                 mCenterPaint.setStyle(Paint.Style.STROKE); 
139.                 if(highlightCenter) { 
140.                     mCenterPaint.setAlpha(0xFF); 
141.                 }else if(highlightCenterLittle) { 
142.                     mCenterPaint.setAlpha(0x90); 
143.                 } 
144.                 canvas.drawCircle(0, 0,  
145.                         centerRadius + mCenterPaint.getStrokeWidth(),  mCenterPaint); 
146.                  
147.                 mCenterPaint.setStyle(Paint.Style.FILL); 
148.                 mCenterPaint.setColor(c); 
149.             } 
150.             //画色环 
151.             canvas.drawOval(new RectF(-r, -r, r, r), mPaint); 
152.             //画黑白渐变块 
153.             if(downInCircle) { 
154.                 mRectColors[1] = mCenterPaint.getColor(); 
155.             } 
156.             rectShader = new LinearGradient(rectLeft, 0, rectRight, 0, mRectColors, null, Shader.TileMode.MIRROR); 
157.             mRectPaint.setShader(rectShader); 
158.             canvas.drawRect(rectLeft, rectTop, rectRight, rectBottom, mRectPaint); 
159.             float offset = mLinePaint.getStrokeWidth() / 2; 
160.             canvas.drawLine(rectLeft - offset, rectTop - offset * 2,  
161.                     rectLeft - offset, rectBottom + offset * 2, mLinePaint);//左 
162.             canvas.drawLine(rectLeft - offset * 2, rectTop - offset,  
163.                     rectRight + offset * 2, rectTop - offset, mLinePaint);//上 
164.             canvas.drawLine(rectRight + offset, rectTop - offset * 2,  
165.                     rectRight + offset, rectBottom + offset * 2, mLinePaint);//右 
166.             canvas.drawLine(rectLeft - offset * 2, rectBottom + offset,  
167.                     rectRight + offset * 2, rectBottom + offset, mLinePaint);//下 
168.             super.onDraw(canvas); 
169.         } 
170.          
171.         @Override 
172.         public boolean onTouchEvent(MotionEvent event) { 
173.             float x = event.getX() - mWidth / 2; 
174.             float y = event.getY() - mHeight / 2 + 50; 
175.             boolean inCircle = inColorCircle(x, y,  
176.                     r + mPaint.getStrokeWidth() / 2, r - mPaint.getStrokeWidth() / 2); 
177.             boolean inCenter = inCenter(x, y, centerRadius); 
178.             boolean inRect = inRect(x, y); 
179.              
180.             switch (event.getAction()) { 
181.                 case MotionEvent.ACTION_DOWN: 
182.                     downInCircle = inCircle; 
183.                     downInRect = inRect; 
184.                     highlightCenter = inCenter; 
185.                 case MotionEvent.ACTION_MOVE: 
186.                     if(downInCircle && inCircle) {//down按在渐变色环内, 且move也在渐变色环内 
187.                         float angle = (float) Math.atan2(y, x); 
188.                         float unit = (float) (angle / (2 * Math.PI)); 
189.                         if (unit < 0) { 
190.                             unit += 1; 
191.                         } 
192.                         mCenterPaint.setColor(interpCircleColor(mCircleColors, unit)); 
193.                         if(debug) Log.v(TAG, "色环内, 坐标: " + x + "," + y); 
194.                     }else if(downInRect && inRect) {//down在渐变方块内, 且move也在渐变方块内 
195.                         mCenterPaint.setColor(interpRectColor(mRectColors, x)); 
196.                     } 
197.                     if(debug) Log.v(TAG, "[MOVE] 高亮: " + highlightCenter + "微亮: " + highlightCenterLittle + " 中心: " + inCenter); 
198.                     if((highlightCenter && inCenter) || (highlightCenterLittle && inCenter)) {//点击中心圆, 当前移动在中心圆 
199.                         highlightCenter = true; 
200.                         highlightCenterLittle = false; 
201.                     } else if(highlightCenter || highlightCenterLittle) {//点击在中心圆, 当前移出中心圆 
202.                         highlightCenter = false; 
203.                         highlightCenterLittle = true; 
204.                     } else { 
205.                         highlightCenter = false; 
206.                         highlightCenterLittle = false; 
207.                     } 
208.                     invalidate(); 
209.                     break; 
210.                 case MotionEvent.ACTION_UP: 
211.                     if(highlightCenter && inCenter) {//点击在中心圆, 且当前启动在中心圆 
212.                         if(mListener != null) { 
213.                             mListener.colorChanged(mCenterPaint.getColor()); 
214.                             ColorPickerDialog.this.dismiss(); 
215.                         } 
216.                     } 
217.                     if(downInCircle) { 
218.                         downInCircle = false; 
219.                     } 
220.                     if(downInRect) { 
221.                         downInRect = false; 
222.                     } 
223.                     if(highlightCenter) { 
224.                         highlightCenter = false; 
225.                     } 
226.                     if(highlightCenterLittle) { 
227.                         highlightCenterLittle = false; 
228.                     } 
229.                     invalidate(); 
230.                     break; 
231.             } 
232.             return true; 
233.         } 
234.  
235.         @Override 
236.         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
237.             super.onMeasure(mWidth, mHeight); 
238.         } 
239.  
240.         /**
241.          * 坐标是否在色环上
242.          * @param x 坐标
243.          * @param y 坐标
244.          * @param outRadius 色环外半径
245.          * @param inRadius 色环内半径
246.          * @return 
247.          */ 
248.         private boolean inColorCircle(float x, float y, float outRadius, float inRadius) { 
249.             double outCircle = Math.PI * outRadius * outRadius; 
250.             double inCircle = Math.PI * inRadius * inRadius; 
251.             double fingerCircle = Math.PI * (x * x + y * y); 
252.             if(fingerCircle < outCircle && fingerCircle > inCircle) { 
253.                 return true; 
254.             }else { 
255.                 return false; 
256.             } 
257.         } 
258.          
259.         /**
260.          * 坐标是否在中心圆上
261.          * @param x 坐标
262.          * @param y 坐标
263.          * @param centerRadius 圆半径
264.          * @return 
265.          */ 
266.         private boolean inCenter(float x, float y, float centerRadius) { 
267.             double centerCircle = Math.PI * centerRadius * centerRadius; 
268.             double fingerCircle = Math.PI * (x * x + y * y); 
269.             if(fingerCircle < centerCircle) { 
270.                 return true; 
271.             }else { 
272.                 return false; 
273.             } 
274.         } 
275.          
276.         /**
277.          * 坐标是否在渐变色中
278.          * @param x
279.          * @param y
280.          * @return 
281.          */ 
282.         private boolean inRect(float x, float y) { 
283.             if( x <= rectRight && x >=rectLeft && y <= rectBottom && y >=rectTop) { 
284.                 return true; 
285.             } else { 
286.                 return false; 
287.             } 
288.         } 
289.          
290.         /**
291.          * 获取圆环上颜色
292.          * @param colors
293.          * @param unit
294.          * @return 
295.          */ 
296.         private int interpCircleColor(int colors[], float unit) { 
297.             if (unit <= 0) { 
298.                 return colors[0]; 
299.             } 
300.             if (unit >= 1) { 
301.                 return colors[colors.length - 1]; 
302.             } 
303.              
304.             float p = unit * (colors.length - 1); 
305.             int i = (int)p; 
306.             p -= i; 
307.  
308.             // now p is just the fractional part [0...1) and i is the index 
309.             int c0 = colors[i]; 
310.             int c1 = colors[i+1]; 
311.             int a = ave(Color.alpha(c0), Color.alpha(c1), p); 
312.             int r = ave(Color.red(c0), Color.red(c1), p); 
313.             int g = ave(Color.green(c0), Color.green(c1), p); 
314.             int b = ave(Color.blue(c0), Color.blue(c1), p); 
315.              
316.             return Color.argb(a, r, g, b); 
317.         } 
318.          
319.         /**
320.          * 获取渐变块上颜色
321.          * @param colors
322.          * @param x
323.          * @return 
324.          */ 
325.         private int interpRectColor(int colors[], float x) { 
326.             int a, r, g, b, c0, c1; 
327.             float p; 
328.             if (x < 0) { 
329.                 c0 = colors[0];  
330.                 c1 = colors[1]; 
331.                 p = (x + rectRight) / rectRight; 
332.             } else { 
333.                 c0 = colors[1]; 
334.                 c1 = colors[2]; 
335.                 p = x / rectRight; 
336.             } 
337.             a = ave(Color.alpha(c0), Color.alpha(c1), p); 
338.             r = ave(Color.red(c0), Color.red(c1), p); 
339.             g = ave(Color.green(c0), Color.green(c1), p); 
340.             b = ave(Color.blue(c0), Color.blue(c1), p); 
341.             return Color.argb(a, r, g, b); 
342.         } 
343.          
344.         private int ave(int s, int d, float p) { 
345.             return s + Math.round(p * (d - s)); 
346.         } 
347.     } 
348.      
349.     /**
350.      * 回调接口
351.      * @author <a href="clarkamx@gmail.com">LynK</a>
352.      * 
353.      * Create on 2012-1-6 上午8:21:05
354.      *
355.      */ 
356.     public interface OnColorChangedListener { 
357.         /**
358.          * 回调函数
359.          * @param color 选中的颜色
360.          */ 
361.         void colorChanged(int color); 
362.     } 
363.      
364.     public String getTitle() { 
365.         return title; 
366.     } 
367.  
368.     public void setTitle(String title) { 
369.         this.title = title; 
370.     } 
371.  
372.     public int getmInitialColor() { 
373.         return mInitialColor; 
374.     } 
375.  
376.     public void setmInitialColor(int mInitialColor) { 
377.         this.mInitialColor = mInitialColor; 
378.     } 
379.  
380.     public OnColorChangedListener getmListener() { 
381.         return mListener; 
382.     } 
383.  
384.     public void setmListener(OnColorChangedListener mListener) { 
385.         this.mListener = mListener; 
386.     } 
387. } 
 
测试界面
PaintDemoActivity.java
Java代码    
1. package com.dwood.paintdemo; 
2.  
3. import android.app.Activity; 
4. import android.content.Context; 
5. import android.os.Bundle; 
6. import android.view.View; 
7. import android.widget.Button; 
8. import android.widget.TextView; 
9.  
10. public class PaintDemoActivity extends Activity { 
11.     Context context; 
12.     private Button btnColorPicker; 
13.     private TextView tvText; 
14.      
15.     private ColorPickerDialog dialog; 
16.      
17.     @Override 
18.     public void onCreate(Bundle savedInstanceState) { 
19.         context = this; 
20.         super.onCreate(savedInstanceState); 
21.         setContentView(R.layout.main); 
22.         initViews(); 
23.     } 
24.     /**
25.      * 初始化UI
26.      */ 
27.     private void initViews() { 
28.         btnColorPicker = (Button) findViewById(R.id.btn_color_picker); 
29.         btnColorPicker.setOnClickListener(new View.OnClickListener() { 
30.              
31.             @Override 
32.             public void onClick(View v) { 
33.                 dialog = new ColorPickerDialog(context, tvText.getTextColors().getDefaultColor(),  
34.                         getResources().getString(R.string.btn_color_picker),  
35.                         new ColorPickerDialog.OnColorChangedListener() { 
36.                      
37.                     @Override 
38.                     public void colorChanged(int color) { 
39.                         tvText.setTextColor(color); 
40.                     } 
41.                 }); 
42.                 dialog.show(); 
43.             } 
44.         }); 
45.         tvText = (TextView) findViewById(R.id.tv_text); 
46.     } 
47. } 

 作者:liaoxianming