val Dp.toPx: Floatget() {var scale = 3f
// MyApplication.context.resources.displayMetrics.apply {
// scale = density
// }return value * scale}val colors = List(360) { i ->Color.hsv(360f - i, 1f, 1f) // 360°到1°的所有HSV颜色
}@Preview
@Composable
fun ColorPicker(color: Color = Color(255, 0, 0),radius:Float = 12f,stroke:Float = 4f,colorCallback:(Color)->Unit = {}) {var x by rememberSaveable{ mutableFloatStateOf(-1f) }var y by rememberSaveable{ mutableFloatStateOf(-1f) }val initialHsv = remember(color) {val (r, g, b) = colorrgbToHsv((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt())}var hsv by rememberSaveable{ mutableStateOf(initialHsv) }var sizeWidth = rememberSaveable{ 300f }LaunchedEffect(color) {val (r, g, b) = colorhsv = rgbToHsv((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt())angleToCoordinates(hsv[0],(sizeWidth - (radius.dp.toPx)) * hsv[1],sizeWidth,(radius.dp.toPx)).let {x = it.firsty = it.second}}LaunchedEffect(x,y) {colorCallback(Color.hsv(hsv[0],hsv[1],hsv[2]))}Canvas(modifier = Modifier.fillMaxWidth().aspectRatio(1f).padding(8.dp).onSizeChanged { size ->sizeWidth = size.width.toFloat() / 2fangleToCoordinates(hsv[0],(sizeWidth - (radius.dp.toPx)) * hsv[1],sizeWidth,(radius.dp.toPx)).let {x = it.firsty = it.second}}.pointerInput(Unit) {awaitEachGesture {val event = awaitPointerEvent(PointerEventPass.Initial)val widthSize: Floatif (event.changes.firstOrNull()?.changedToDown() == true) {widthSize = size.width.toFloat()var newValue = Offset(x = event.changes.first().position.x,y = event.changes.first().position.y)var circle = pointToCircle(newValue.x,newValue.y,widthSize)if (widthSize / 4f < circle &&widthSize / 2f > circle) {val xy =findPoint(newValue.x,newValue.y,circle,widthSize,radius.dp.toPx())hsv[0] = angle(xy.first, xy.second, widthSize)hsv[1] = (circle / (widthSize / 2)).coerceIn(0.5f, 1f)x = xy.firsty = xy.second}val down = awaitFirstDown(requireUnconsumed = true)var drag: PointerInputChange?do {drag = awaitTouchSlopOrCancellation(down.id) { change, _ ->if (change.positionChange() != Offset.Zero) change.consume()}} while (drag != null && !drag.isConsumed)if (drag != null) {!drag(drag.id) {newValue = Offset(x = it.position.x,y = it.position.y)circle = pointToCircle(newValue.x,newValue.y,widthSize)val xy = findPoint(newValue.x,newValue.y,circle,widthSize,radius.dp.toPx())hsv[0] = angle(xy.first, xy.second, widthSize)hsv[1] = (circle / (widthSize / 2)).coerceIn(0.5f, 1f)x = xy.firsty = xy.secondif (it.positionChange() != Offset.Zero) it.consume()}}}}}) {//初始化if(x == -1f){x = size.width - radius.dp.toPx() - strokey = size.height/2}//hsv的渐变色drawCircle(brush = Brush.sweepGradient(colors = colors),style = Stroke(width = size.width / 4),radius = size.width / 8 * 3)//中心渐变色drawCircle(brush = Brush.radialGradient(colors = listOf(Color.White,Color.Transparent),radius = size.width / 2),style = Stroke(width = size.width / 4),radius = size.width / 8 * 3)//外黑色边框drawCircle(color= Color.Black,style = Stroke(width = stroke/5f),radius = size.width / 2)//内黑色边框drawCircle(color= Color.Black,style = Stroke(width = stroke/5f),radius = size.width / 4)//圆drawCircle(color = Color.hsv(hsv[0],hsv[1],hsv[2]),radius = radius.dp.toPx(),style = Fill,center = Offset(x,y))//圆黑色边框drawCircle(color = Color.Gray,radius = radius.dp.toPx(),style = Stroke(width = stroke),center = Offset(x,y))}
}@Preview
@Composable
fun ColorPicker2(color: Color = Color(255, 0, 0), radius:Float = 12f, stroke:Float = 4f, colorCallback:(Color)->Unit = {}) {var x by rememberSaveable{ mutableFloatStateOf(-1f) }var y by rememberSaveable{ mutableFloatStateOf(-1f) }val initialHsv = remember(color) {val (r, g, b) = colorrgbToHsv((r * 255).toInt(),(g * 255).toInt(),(b * 255).toInt())}var hsv by rememberSaveable{ mutableStateOf(initialHsv) }var sizeWidth = rememberSaveable{ 300f }LaunchedEffect(color) {val (r, g, b) = colorhsv = rgbToHsv((r * 255).toInt(),(g * 255).toInt(),(b * 255).toInt())angleToCoordinates(hsv[0],(sizeWidth - (radius.dp.toPx)) * hsv[1],sizeWidth,(radius.dp.toPx)).let {x = it.firsty = it.second}}LaunchedEffect(x,y) {colorCallback(Color.hsv(hsv[0],hsv[1],hsv[2]))}Canvas(modifier = Modifier.fillMaxWidth().aspectRatio(1f).padding(8.dp).onSizeChanged { size ->sizeWidth = size.width.toFloat() / 2fangleToCoordinates(hsv[0],(sizeWidth - (radius.dp.toPx)) * hsv[1],sizeWidth,(radius.dp.toPx)).let {x = it.firsty = it.second}}.pointerInput(Unit) {awaitEachGesture {val event = awaitPointerEvent(PointerEventPass.Initial)val widthSize: Floatif (event.changes.firstOrNull()?.changedToDown() == true) {widthSize = size.width.toFloat()var newValue = Offset(x = event.changes.first().position.x,y = event.changes.first().position.y)var circle = pointToCircle(newValue.x, newValue.y, widthSize)if (widthSize / 2f > circle) {val xy = findPoint2(newValue.x, newValue.y, circle, widthSize, radius.dp.toPx())hsv[0] = angle(xy.first, xy.second, widthSize)hsv[1] = (circle / (widthSize / 2)).coerceIn(0f, 1f)x = xy.firsty = xy.second}val down = awaitFirstDown(requireUnconsumed = true)var drag: PointerInputChange?do {drag = awaitTouchSlopOrCancellation(down.id) { change, _ ->if (change.positionChange() != Offset.Zero) change.consume()}} while (drag != null && !drag.isConsumed)if (drag != null) {!drag(drag.id) {newValue = Offset(x = it.position.x,y = it.position.y)circle = pointToCircle(newValue.x, newValue.y, widthSize)val xy = findPoint2(newValue.x,newValue.y,circle,widthSize,radius.dp.toPx())hsv[0] = angle(xy.first, xy.second, widthSize)hsv[1] = (circle / (widthSize / 2)).coerceIn(0f, 1f)x = xy.firsty = xy.secondif (it.positionChange() != Offset.Zero) it.consume()}}}}}) {//初始化if(x == -1f){x = size.width - radius.dp.toPx() - strokey = size.height/2}//hsv的渐变色drawCircle(brush = Brush.sweepGradient(colors = colors),style = Fill,radius = size.width / 2)//中心渐变色drawCircle(brush = Brush.radialGradient(colors = listOf(Color.White,Color.Transparent),radius = size.width / 2),style = Fill,radius = size.width / 2)//外黑色边框drawCircle(color= Color.Black,style = Stroke(width = stroke/5f),radius = size.width / 2)//圆drawCircle(color = Color.hsv(hsv[0],hsv[1],hsv[2]),radius = radius.dp.toPx(),style = Fill,center = Offset(x,y))//圆黑色边框drawCircle(color = Color.Gray,radius = radius.dp.toPx(),style = Stroke(width = stroke),center = Offset(x,y))}
}// 离目标最近的点 待开发
private fun findPoint(x1: Float,y1: Float,circle: Float,size:Float,colorRadius:Float,colorStroke:Float = 0f
): Pair<Float,Float>{var r = size / 2f - (colorRadius + colorStroke)when{circle > (size/2f - colorRadius)->{}circle < (size/4f + colorRadius)->{r = size / 4f + (colorRadius + colorStroke)}else -> {return x1 to y1}}val a = y1 - size / 2fval b = x1 - size / 2fvar yColor = sqrt((r * r) / ((b / a) * (b / a) + 1))if (a < 0) yColor = -yColorval xColor = (b * yColor) / a + size / 2fyColor += size / 2freturn xColor to yColor
}// 离目标最近的点 待开发
private fun findPoint2(x1: Float,y1: Float,circle: Float,size:Float,colorRadius:Float,colorStroke:Float = 0f
): Pair<Float,Float>{var r = size / 2f - (colorRadius + colorStroke)when{circle > (size/2f - colorRadius)->{}else -> {return x1 to y1}}val a = y1 - size / 2fval b = x1 - size / 2fvar yColor = sqrt((r * r) / ((b / a) * (b / a) + 1))if (a < 0) yColor = -yColorval xColor = (b * yColor) / a + size / 2fyColor += size / 2freturn xColor to yColor
}// 点到圆心距离
fun pointToCircle(x: Float, y: Float, size:Float) =sqrt((x - size / 2f).pow(2) + (y - size / 2f).pow(2))private const val RAD_TO_DEG = 180f / Math.PI.toFloat()// 角度
private fun angle(x: Float, y: Float, size: Float): Float {val dx = x - size / 2fval dy = y - size / 2fvar deg = atan2(-dy, dx) * RAD_TO_DEGif (deg < 0) deg += 360freturn deg.coerceIn(0f,360f)
}private const val DEG_TO_RAD = Math.PI.toFloat() / 180fprivate fun angleToCoordinates(angleDeg: Float, radius: Float, _radius: Float, size: Float): Pair<Float, Float> {// 将角度转换为弧度val angleRad = angleDeg * DEG_TO_RAD// 计算x和y坐标(相对于中心)val dx = radius * cos(angleRad)val dy = -radius * sin(angleRad)// 转换为绝对坐标val x = dx + _radiusval y = dy + _radiusreturn Pair(x, y)
}fun rgbToHsv(r: Int, g: Int, b: Int): FloatArray {// 参数校验require(r in 0..255) { "Red component must be between 0 and 255" }require(g in 0..255) { "Green component must be between 0 and 255" }require(b in 0..255) { "Blue component must be between 0 and 255" }// 将RGB分量归一化到[0,1]范围val rNorm = r / 255fval gNorm = g / 255fval bNorm = b / 255fval cmax = max(max(rNorm, gNorm), bNorm)val cmin = min(min(rNorm, gNorm), bNorm)val delta = cmax - cmin// 计算色相(H)val h = when {delta == 0f -> 0fcmax == rNorm -> 60f * (((gNorm - bNorm) / delta) % 6f)cmax == gNorm -> 60f * (((bNorm - rNorm) / delta) + 2f)else -> 60f * (((rNorm - gNorm) / delta) + 4f)}.let { if (it < 0) it + 360f else it }// 计算饱和度(S)val s = when {cmax == 0f -> 0felse -> delta / cmax}// 明度(V)就是cmaxval v = cmaxreturn floatArrayOf(h, s, v)
}