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.javaJava代码
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