自定义View
![](https://img-blog.csdnimg.cn/img_convert/2d1963e258c7fb481d9968c190cd229d.gif)
![](https://img-blog.csdnimg.cn/img_convert/641e2dd6d92992b67cad980fcc564aef.gif)
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
![](https://img-blog.csdnimg.cn/img_convert/585301684af91ea68b5aee9a5440f506.gif)
![](https://img-blog.csdnimg.cn/img_convert/6057f5c312128dc032c3a70b6334329d.gif)
@OptIn(ExperimentalGraphicsApi::class)
@Composable
fun colorPicker(radius:Float,stroke:Float) {
val colorCount = 360
val colorAngleStep = 360 / colorCount
val colors = mutableListOf<Color>()
//存储选中颜色
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)
)
}
}