Android 颜色选择器 自定义漂亮色环 提供事件回调
先上效果图:
先来啰嗦几句,哈哈哈
此控件真是一波三折啊,算了,还是直接说最终代码流程吧
先说使用流程:
1.XML配置
<com.zhuoapp.opple.view.ColorTouchView android:id="@+id/color_view" android:layout_width="wrap_content" android:layout_height="wrap_content" />
2.UI绑定事件,是不是很简单
mColorView.setOnColorViewTouchListener(new OnColorViewTouchListener() { @Override public void onUpEvent(final int color) { } @Override public void onMoveEvent(int color) { } @Override public void onDownEvent(int color) { } @Override public void onCancelEvent(int color) { } });
3.整个类源码如下
public class ColorTouchView extends View { // 画笔抗锯齿 public Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 渐变色环画笔 public Paint mPaintLoc = new Paint(Paint.ANTI_ALIAS_FLAG);// public Paint mPaintFilter = new Paint(Paint.ANTI_ALIAS_FLAG);// // 三十六个色相RGB值,存放默认HSL转化来的RGB值 // (H对应360度平分36份的点,S对应为饱和度[默认为0.5],L对应为亮度[默认为0.5]) public int[] mCircleColors = new int[36]; private int alpha = 255; public Shader s; private RadialGradient radialGradient; public int num = 36; public int[] colorArray = new int[num]; public int currColor = Color.argb(255, 235, 235, 235); private int borderColor = Color.parseColor("#aeaeae"); private int pointColor = Color.parseColor("#ffffff"); // 取色圆的初始位置为颜色盘的最右侧 public int x_touchCircle;// 初始化取色圆的圆心的x坐标为宽度的90% public int y_touchCircle;// 初始化取色圆的圆心的y坐标为高度的50% // 小圆半径 public int r_touchCircle = dip2px(6); public int touchAreaDis = dip2px(20); public int height; // 屏幕高度 public int width;// 屏幕宽度 public int step = 0;// 绘制次数 public int Rmax;// 最大半径为宽度的40% public int Rmin;// 最小半径为宽度的26.1955%(经过计算) private static int x_circle, y_circle; private RectF mRectF; private long lastTouchUpTime, currTouchDownTime; private Context mContext; public ColorTouchView(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; } protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (x_touchCircle == 0) x_touchCircle = (int) (width * 0.9); if (y_touchCircle == 0) y_touchCircle = (int) (height * 0.5); calLocation(); // for (int j = 0; j < step; j++) { int j = 0; for (int w = 0; w < num - 1; w++) { colorArray[w] = ColorUtil.HSL2RGB(new double[]{ 360.0 / num * w, 1 - 0.6 / step * j, 1}); } colorArray[num - 1] = colorArray[0]; for (int i = 0; i < num; i++) { mCircleColors[i] = Color.argb(alpha, Color.red(colorArray[i]), Color.green(colorArray[i]), Color.blue(colorArray[i])); } s = new SweepGradient(x_circle, y_circle, mCircleColors, null); mPaint.setShader(s); canvas.drawCircle(x_circle, y_circle, Rmax - step / 2, mPaint); //画外部轮廓 canvas.drawCircle(x_circle,y_circle,Rmax+r_touchCircle/2,mPaintLoc); // } //画透明度 canvas.drawCircle(x_circle, y_circle, Rmax - step / 2, mPaintFilter); mPaint.setColor(borderColor); // 画外部轮廊 canvas.drawCircle(x_circle, y_circle, Rmax, mPaintLoc); // 画内部轮廊 canvas.drawCircle(x_circle, y_circle, Rmin, mPaintLoc); // canvas.drawBitmap(((BitmapDrawable) gd).getBitmap()); // 画圆点 mPaint.setColor(pointColor); mPaintLoc.setStrokeWidth(dip2px(1)); if (!touchFlag) { canvas.drawCircle(x_touchCircle, y_touchCircle, r_touchCircle, mPaintLoc); } } private boolean touchFlag = false; @Override public boolean onTouchEvent(MotionEvent event) { // 圆心坐标 x_circle = (int) (width * 0.5); y_circle = (int) (height * 0.5); currTouchDownTime = System.currentTimeMillis(); // 两次调色时间需要大于400s if (currTouchDownTime - lastTouchUpTime > 400) { // 触摸点 int aimX = (int) event.getX(); int aimY = (int) event.getY(); double temp = (aimX - x_circle) * (aimX - x_circle) + (aimY - y_circle) * (aimY - y_circle); double currR = Math.sqrt(temp); // int zone = (int) (currR - Rmin); // 是否色环上 boolean isCir = currR >= Rmin-touchAreaDis && currR <= Rmax +touchAreaDis; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (isCir) { touchFlag = true; invalidate(); currColor = ColorUtil.position2RGB(aimX, aimY, x_circle, y_circle, Rmax, Rmin); if (onColorViewTouchListener != null) { onColorViewTouchListener.onDownEvent(currColor); } } case MotionEvent.ACTION_MOVE: if (isCir && touchFlag) { currColor = ColorUtil.position2RGB(aimX, aimY, x_circle, y_circle, Rmax, Rmin); if (onColorViewTouchListener != null) { onColorViewTouchListener.onMoveEvent(currColor); } } break; case MotionEvent.ACTION_UP: if (isCir && touchFlag) { currColor = ColorUtil.position2RGB(aimX, aimY, x_circle, y_circle, Rmax, Rmin); if (onColorViewTouchListener != null) { onColorViewTouchListener.onUpEvent(currColor); } } touchFlag = false; setCurrColor(currColor); lastTouchUpTime = System.currentTimeMillis(); break; default: break; } } return true; } // 设置初始值 public void setCurrColor(int color) { this.currColor = color; invalidate(); } /** * 根据颜色计算位置 */ private void calLocation() { double[] convertedHsl = ColorUtil.RGB2HSL(currColor); double angle = convertedHsl[0]; double saturation = convertedHsl[1]; // 所在点距内环的距离 double distance = Rmax * saturation - Rmin; distance = distance < 0 ? 0 : distance; distance = distance > (Rmax - Rmin) ? (Rmax - Rmin) : distance; double currColorR = Rmin + distance; if (currColorR > Rmax) { currColorR = Rmax; } double radians = Math.toRadians(angle); x_touchCircle = (int) (currColorR * Math.cos(radians) + width * .5); y_touchCircle = (int) (currColorR * Math.sin(radians) + height * .5); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); height = MeasureSpec.getSize(widthMeasureSpec); width = height; Rmax = (int) (width * 0.46); Rmin = (int) (width * 0.46 * .36); step = Rmax - Rmin; int r = Rmax - step / 2; mRectF = new RectF(x_circle - r, y_circle - r, x_circle + r, y_circle + r); x_circle = (int) (width * 0.5); y_circle = (int) (height * 0.5); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(step); mPaintLoc.setStyle(Paint.Style.STROKE);// 设置空心 mPaintLoc.setColor(borderColor); mPaintLoc.setStrokeWidth(dip2px(1)); int sc = Color.parseColor("#e0FFFFFF"); int ec = Color.parseColor("#00ffffff"); int startAlpha = Color.alpha(sc); int endAlpha = Color.alpha(ec); int[] colors = new int[Rmax]; float[] pos = new float[Rmax]; for (int i = 0; i < Rmax; i++) { if (i < Rmin) { colors[i] = Color.TRANSPARENT; } else { pos[i] = (float) Math.sin((i - Rmin + 1) * 1.0f / step); int a = startAlpha - (int) ((startAlpha - endAlpha) * pos[i]); colors[i] = Color.argb(a, Color.red(sc), Color.green(sc), Color.blue(sc)); } pos[i] = (i + 1) * 1.0f / Rmax; } radialGradient = new RadialGradient(x_circle, y_circle, Rmax, colors, pos, Shader.TileMode.REPEAT); mPaintFilter.setShader(radialGradient); mPaintFilter.setStyle(Paint.Style.STROKE); mPaintFilter.setStrokeWidth(step); mPaintFilter.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); setMeasuredDimension(widthMeasureSpec, widthMeasureSpec); } /* android.graphics.PorterDuff.Mode.SRC:只绘制源图像 android.graphics.PorterDuff.Mode.DST:只绘制目标图像 android.graphics.PorterDuff.Mode.DST_OVER:在源图像的顶部绘制目标图像 android.graphics.PorterDuff.Mode.DST_IN:只在源图像和目标图像相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.DST_OUT:只在源图像和目标图像不相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.DST_ATOP:在源图像和目标图像相交的地方绘制目标图像,在不相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_OVER:在目标图像的顶部绘制源图像 android.graphics.PorterDuff.Mode.SRC_IN:只在源图像和目标图像相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_OUT:只在源图像和目标图像不相交的地方绘制源图像 android.graphics.PorterDuff.Mode.SRC_ATOP:在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像 android.graphics.PorterDuff.Mode.XOR:在源图像和目标图像重叠之外的任何地方绘制他们,而在不重叠的地方不绘制任何内容 android.graphics.PorterDuff.Mode.LIGHTEN:获得每个位置上两幅图像中最亮的像素并显示 android.graphics.PorterDuff.Mode.DARKEN:获得每个位置上两幅图像中最暗的像素并显示 android.graphics.PorterDuff.Mode.MULTIPLY:将每个位置的两个像素相乘,除以255,然后使用该值创建一个新的像素进行显示。结果颜色=顶部颜色*底部颜色/255 android.graphics.PorterDuff.Mode.SCREEN:反转每个颜色,执行相同的操作(将他们相乘并除以255),然后再次反转。结果颜色=255-(((255-顶部颜色)*(255-底部颜色))/255) */ public boolean inOutCircle(float x, float y, float outRadius, float inRadius) { double outCircle = outRadius; double inCircle = inRadius; double fingerCircle = Math.sqrt(x * x + y * y); if (fingerCircle <= outCircle && fingerCircle >= inCircle) { return true; } else { return false; } } private OnColorViewTouchListener onColorViewTouchListener; public void setOnColorViewTouchListener( OnColorViewTouchListener onColorViewTouchListener) { this.onColorViewTouchListener = onColorViewTouchListener; } public interface OnColorViewTouchListener { public void onUpEvent(int color); public void onDownEvent(int color); public void onMoveEvent(int color); public void onCancelEvent(int color); } private int dip2px(float dpValue) { final float scale = getContext().getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } }