Android 顏色選擇器(ColorPicker)

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

發佈留言