Android 自定义Canvas取色盘 和 自定义View取色盘
自定义View
public class ColorsHSV360 extends View { private Context mContext; private Paint mPaint; //父布局宽高 private int measureHeigth, measureWidth; private float radius = 40, stroke = 5; private float x = -1,y = -1; //子布局位置 //圆参数 private Event event; private int color = Color.WHITE; public ColorsHSV360(Context context) { super(context); init(context); } public ColorsHSV360(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ColorsHSV360(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mContext = context; mPaint = new Paint(); mPaint.setAntiAlias(true); // 消除锯齿 } public void setEvent(Event event){ this.event = event; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { boolean isInit = false; if(MeasureSpec.getSize(heightMeasureSpec)==measureHeigth && MeasureSpec.getSize(widthMeasureSpec)==measureWidth){ isInit = true; } measureHeigth = MeasureSpec.getSize(heightMeasureSpec); measureWidth = MeasureSpec.getSize(widthMeasureSpec); if(!isInit){ setXY(color); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { createColorWheelBitmap(radius+stroke, (int) (measureWidth-2*(radius+stroke)), (int) (measureHeigth-2*(radius+stroke)), (int) (radius+stroke)*2, canvas); }else { canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.colorblock_2),null, new RectF(0,0,measureWidth,measureHeigth),null); } createCircleImage(canvas); super.onDraw(canvas); } @Override public boolean onTouchEvent(MotionEvent e) { x = (int) e.getX(); x = Math.min(Math.max(x, radius+stroke), measureWidth-radius-stroke); y = (int) e.getY(); y = Math.min(Math.max(y, radius+stroke), measureHeigth-radius-stroke); int hsvToColor = Color.HSVToColor(new float[]{ ((x-(radius+stroke)) / (measureWidth-2f*(radius+stroke))) * 360, (y-(radius+stroke)) / (measureHeigth-2f*(radius+stroke)), 1f}); int iMaskAct = e.getAction() & MotionEvent.ACTION_MASK; if(event != null){ int red = (hsvToColor & 0x00ff0000) >> 16; int green = (hsvToColor & 0x0000ff00) >> 8; int blue = (hsvToColor & 0x000000ff); event.getColors(red,green,blue,iMaskAct == MotionEvent.ACTION_UP); } invalidate(); return true; } //设置颜色 public void setXY(Integer color){ float[] hsv = new float[3]; Color.colorToHSV(color,hsv); this.x =hsv[0]/360*(measureWidth-2*radius-2*stroke)+radius+stroke; this.y =hsv[1] * (measureHeigth-2*radius-2*stroke)+radius+stroke; if(event != null){ int red = (color & 0x00ff0000) >> 16; int green = (color & 0x0000ff00) >> 8; int blue = (color & 0x000000ff); event.getColors(red,green,blue,true); } invalidate(); } //创建色盘背景Bitmap private void createColorWheelBitmap(float radius,int width, int height, int topRadius, Canvas canvas) { mPaint.reset(); mPaint.setFlags(Paint.ANTI_ALIAS_FLAG); int colorCount = 360; int colorAngleStep = 360 / colorCount; int[] colors = new int[colorCount + 1]; float[] hsv = new float[]{0f, 1f, 1f}; for (int i = 0; i < colors.length; i++) { hsv[0] = (i * colorAngleStep) % 360; colors[i] = Color.HSVToColor(hsv); } colors[colorCount] = colors[0]; LinearGradient linearGradient1 = new LinearGradient(radius,radius,width,radius,colors,null, Shader.TileMode.CLAMP); LinearGradient linearGradient2 = new LinearGradient(radius,radius,radius,height,Color.argb(255,255,255,255),Color.argb(0,255,255,255),Shader.TileMode.CLAMP); ComposeShader composeShader = new ComposeShader(linearGradient1, linearGradient2, PorterDuff.Mode.SRC_OVER); mPaint.setShader(composeShader); Path path = new Path(); path.arcTo(new RectF(0, 0, topRadius, topRadius),180,90); path.arcTo(new RectF(width - topRadius + 2* radius , 0, width + 2*radius, topRadius),270,90); path.lineTo(width+2*radius,height+2*radius); path.lineTo(0,height+2*radius); path.close(); canvas.drawPath(path, mPaint); } /** * 一个圆 */ private void createCircleImage(Canvas canvas) { mPaint.reset(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); int hsvToColor = Color.HSVToColor(new float[]{ ((x-(radius+stroke)) / (measureWidth-2f*(radius+stroke))) * 360, (y-(radius+stroke)) / (measureHeigth-2f*(radius+stroke)), 1f}); mPaint.setColor(hsvToColor); canvas.drawCircle(x,y, radius, mPaint); mPaint.setStrokeWidth(stroke); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.parseColor("#FFEAEAEA")); canvas.drawCircle(x,y, radius, mPaint); mPaint.setStrokeWidth(stroke-2); mPaint.setColor(Color.parseColor("#FFFFFFFF")); canvas.drawCircle(x,y, radius+2, mPaint); } public interface Event{ void getColors(int red,int green,int blue,boolean up); } }
定义Canvas
@OptIn(ExperimentalGraphicsApi::class) @Composable fun colorPicker(radius:Float,stroke:Float) { val colorCount = 360 val colorAngleStep = 360 / colorCount val colors = mutableListOf() //存储选中颜色 val hsv = floatArrayOf(0f, 1f, 1f) for (i in 0..colorCount) { hsv[0] = (i * colorAngleStep % 360).toFloat() colors.add(Color.hsv(hsv[0],hsv[1],hsv[2])) } val x = rememberSaveable{ mutableStateOf(-1f) } val y = rememberSaveable{ mutableStateOf(-1f) } Canvas(modifier = Modifier .fillMaxWidth() .height(200.dp) .padding(5.dp) .pointerInput(Unit) { forEachGesture { awaitPointerEventScope { //PointerEventPass.Initial解决点击和拖动的冲突 val event = awaitPointerEvent(PointerEventPass.Initial) if(event.changes.firstOrNull()?.changedToDown() == true) { var newValue = Offset( x = event.changes.first().position.x.coerceIn(radius.dp.toPx()+stroke, size.width - radius.dp.toPx()-stroke), y = event.changes.first().position.y.coerceIn(radius.dp.toPx()+stroke, size.height - radius.dp.toPx()-stroke) ) x.value = newValue.x y.value = newValue.y hsv[0] = (newValue.x-(radius.dp.toPx()+stroke)) / (size.width - 2* radius.dp.toPx()) * 360 hsv[1] = (newValue.y-(radius.dp.toPx()+stroke)) / (size.height - 2* radius.dp.toPx()) Log.d("TAG","newValue111-->$newValue") val down = awaitFirstDown(requireUnconsumed = true) var drag: PointerInputChange? do { drag = awaitTouchSlopOrCancellation(down.id) { change, _ -> change.consumePositionChange() } } while (drag != null && !drag.positionChangeConsumed()) if (drag != null) { !drag(drag.id) { newValue = Offset( x = it.position.x.coerceIn(radius.dp.toPx()+stroke, size.width - radius.dp.toPx()-stroke), y = it.position.y.coerceIn(radius.dp.toPx()+stroke, size.height - radius.dp.toPx()-stroke) ) x.value = newValue.x y.value = newValue.y hsv[0] = (newValue.x-(radius.dp.toPx()+stroke)) / (size.width - 2* radius.dp.toPx()) * 360 hsv[1] = (newValue.y-(radius.dp.toPx()+stroke)) / (size.height - 2* radius.dp.toPx()) Log.d("TAG","newValue333-->$newValue") it.consumePositionChange() } } } } } } ) { //初始化 if(x.value == -1f){ x.value = radius.dp.toPx()+stroke y.value = radius.dp.toPx()+stroke hsv[0] = 0f; hsv[1] = 0f; hsv[2] = 1f; } //hsv h 的渐变色 drawRoundRect( brush = Brush.horizontalGradient(colors = colors, startX = radius.dp.toPx(), endX = size.width -radius.dp.toPx()), cornerRadius = CornerRadius(radius.dp.toPx(), radius.dp.toPx()), style = Fill, size = Size(size.width , size.height) ) //白色到透明的渐变色 drawRoundRect( brush = Brush.verticalGradient(colors = listOf(Color.White, Color.Transparent), startY = radius.dp.toPx(), endY = size.height-radius.dp.toPx()), cornerRadius = CornerRadius(radius.dp.toPx(), radius.dp.toPx()), style = Fill, size = Size(size.width , size.height) ) //白色边框 drawRoundRect( color= Color.White, cornerRadius = CornerRadius(radius.dp.toPx(), radius.dp.toPx()), style = Stroke(width = stroke), topLeft = Offset(stroke/2f, stroke/2f), size = Size(size.width-stroke, size.height-stroke) ) //黑色边框 drawRoundRect( color= Color.Black, cornerRadius = CornerRadius(radius.dp.toPx(), radius.dp.toPx()), style = Stroke(width = stroke/5f), topLeft = Offset(stroke, stroke), size = Size(size.width-2*stroke, size.height-2*stroke) ) //圆 drawCircle( color = Color.hsv(hsv[0],hsv[1],hsv[2]), radius = radius.dp.toPx(), style = Fill, center = Offset(x.value,y.value) ) //圆黑色边框 drawCircle( color = Color.Gray, radius = radius.dp.toPx()-stroke, style = Stroke(width = stroke), center = Offset(x.value,y.value) ) //白色黑色边框 drawCircle( color = Color.White, radius = radius.dp.toPx()-stroke/2, style = Stroke(width = stroke), center = Offset(x.value,y.value) ) } }