如何使用 Jetpack Compose 创建 HSL 饱和度和亮度变化渐变或画笔编辑器?
How to create HSL saturation and lightness change gradient or brush editor with Jetpack Compose?
我正在使用 Jetpack Compose 构建颜色选择器,并尝试实现饱和度和亮度选择器菱形(矩形旋转 45 度),如图像所示,但无法找到显示颜色的好方法他们应该看起来像
我可以在菱形中找到位置并用左边的图像画圆圈,因为那些是圆圈,所以看起来不太好。还尝试绘制小路径,但它会显着降低应用程序速度。
/**
* Get each point and saturation and lightness of the point. This function is for
* creating points to draw like gradient effect for HSL color
*/
fun getPointsInRhombus(length: Float): MutableList<ColorPoint> {
val step = length.toInt() / 50
val colorPoints = mutableListOf<ColorPoint>()
for (yPos in 0..length.toInt() step step) {
val range = getIntRangeInLength(length = length, yPos.toFloat())
for (xPos in range step step) {
val path = rhombusPath(Size(10f, 10f))
path.translate(Offset(xPos.toFloat() - 5, yPos.toFloat()))
val saturation = xPos / length
val lightness = 1 - (yPos / length)
val colorPoint =
ColorPoint(Offset(xPos.toFloat(), yPos.toFloat()), saturation, lightness, path)
colorPoints.add(colorPoint)
}
}
return colorPoints
}
colorPoints.forEach { colorPoint: ColorPoint ->
drawCircle(
Color.hsl(hue, colorPoint.saturation, colorPoint.lightness),
center = colorPoint.point,
radius = 10f
)
}
还尝试创建一个用于亮度的形状和另一个用于饱和度的形状,并尝试将它们混合在一起,但它不起作用,如右图所示。
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
// Destination lightness top to bottom
drawPath(
rhombusPath, Brush.verticalGradient(
colors = listOf(
Color.hsl(
hue,
saturation = .5f,
lightness = 1f,
alpha = 1f
),
Color.hsl(
hue,
saturation = .5f,
lightness = 0f,
alpha = 1f
)
)
)
)
// Source saturation left to right
drawPath(
rhombusPath,
Brush.horizontalGradient(
colors = listOf(
Color.hsl(
hue,
saturation = 0f,
lightness = .5f,
alpha = 1f
),
Color.hsl(
hue,
saturation = 1f,
lightness = .5f,
alpha = 1f
)
)
),
blendMode = BlendMode.SrcIn
)
restoreToCount(checkPoint)
}
我需要的是将第一个图像中的颜色应用于右侧的菱形图像,而不绘制圆圈或路径。我认为这可以通过一个渐变或多个渐变或混合它们来解决,但不知道如何解决。
查看此 以供参考,但无法弄清楚如何将其应用于 Compose Brush
对于HSL梯度 BlendMode.Multiply
不起作用,它适用于获得HSV梯度。解决方案是使用 Blendmode.Overlay 渐变。另外 Brush.linergradient 的默认角度是 45 度 顺时针,需要将其设置为 0 度 才能使饱和度从头到尾发生变化可组合的。
val lightnessGradient = remember {
Brush.verticalGradient(
colors = listOf(
Color.hsl(hue = hue, saturation = .5f, lightness = 1f),
Color.hsl(hue = hue, saturation = .5f, lightness = 0f)
)
)
}
val saturationHSLGradient = remember {
val gradientOffset = GradientOffset(GradientAngle.CW0)
Brush.linearGradient(
colors = listOf(
Color.hsl(hue, 0f, .5f),
Color.hsl(hue, 1f, .5f)
),
start = gradientOffset.start,
end = gradientOffset.end
)
}
然后在图层中使用叠加的 Blend(PorterDuff) 模式绘制这两个渐变
Canvas(modifier = canvasModifier) {
drawIntoLayer {
drawPath(
path = rhombusPath,
lightnessGradient,
)
drawPath(
path = rhombusPath,
saturationHSLGradient,
blendMode = BlendMode.Overlay
)
}
}
混合绘图功能
fun DrawScope.drawIntoLayer(
content: DrawScope.() -> Unit
) {
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
content()
restoreToCount(checkPoint)
}
}
HSV 和 HSL 渐变的结果,小矩形不是用渐变绘制的,而是在点处绘制小矩形以验证 HSL 渐变与位置处的真实颜色匹配。
Github 完整实施的回购可用 here。
我正在使用 Jetpack Compose 构建颜色选择器,并尝试实现饱和度和亮度选择器菱形(矩形旋转 45 度),如图像所示,但无法找到显示颜色的好方法他们应该看起来像
我可以在菱形中找到位置并用左边的图像画圆圈,因为那些是圆圈,所以看起来不太好。还尝试绘制小路径,但它会显着降低应用程序速度。
/**
* Get each point and saturation and lightness of the point. This function is for
* creating points to draw like gradient effect for HSL color
*/
fun getPointsInRhombus(length: Float): MutableList<ColorPoint> {
val step = length.toInt() / 50
val colorPoints = mutableListOf<ColorPoint>()
for (yPos in 0..length.toInt() step step) {
val range = getIntRangeInLength(length = length, yPos.toFloat())
for (xPos in range step step) {
val path = rhombusPath(Size(10f, 10f))
path.translate(Offset(xPos.toFloat() - 5, yPos.toFloat()))
val saturation = xPos / length
val lightness = 1 - (yPos / length)
val colorPoint =
ColorPoint(Offset(xPos.toFloat(), yPos.toFloat()), saturation, lightness, path)
colorPoints.add(colorPoint)
}
}
return colorPoints
}
colorPoints.forEach { colorPoint: ColorPoint ->
drawCircle(
Color.hsl(hue, colorPoint.saturation, colorPoint.lightness),
center = colorPoint.point,
radius = 10f
)
}
还尝试创建一个用于亮度的形状和另一个用于饱和度的形状,并尝试将它们混合在一起,但它不起作用,如右图所示。
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
// Destination lightness top to bottom
drawPath(
rhombusPath, Brush.verticalGradient(
colors = listOf(
Color.hsl(
hue,
saturation = .5f,
lightness = 1f,
alpha = 1f
),
Color.hsl(
hue,
saturation = .5f,
lightness = 0f,
alpha = 1f
)
)
)
)
// Source saturation left to right
drawPath(
rhombusPath,
Brush.horizontalGradient(
colors = listOf(
Color.hsl(
hue,
saturation = 0f,
lightness = .5f,
alpha = 1f
),
Color.hsl(
hue,
saturation = 1f,
lightness = .5f,
alpha = 1f
)
)
),
blendMode = BlendMode.SrcIn
)
restoreToCount(checkPoint)
}
我需要的是将第一个图像中的颜色应用于右侧的菱形图像,而不绘制圆圈或路径。我认为这可以通过一个渐变或多个渐变或混合它们来解决,但不知道如何解决。
查看此 Brush
对于HSL梯度 BlendMode.Multiply
不起作用,它适用于获得HSV梯度。解决方案是使用 Blendmode.Overlay 渐变。另外 Brush.linergradient 的默认角度是 45 度 顺时针,需要将其设置为 0 度 才能使饱和度从头到尾发生变化可组合的。
val lightnessGradient = remember {
Brush.verticalGradient(
colors = listOf(
Color.hsl(hue = hue, saturation = .5f, lightness = 1f),
Color.hsl(hue = hue, saturation = .5f, lightness = 0f)
)
)
}
val saturationHSLGradient = remember {
val gradientOffset = GradientOffset(GradientAngle.CW0)
Brush.linearGradient(
colors = listOf(
Color.hsl(hue, 0f, .5f),
Color.hsl(hue, 1f, .5f)
),
start = gradientOffset.start,
end = gradientOffset.end
)
}
然后在图层中使用叠加的 Blend(PorterDuff) 模式绘制这两个渐变
Canvas(modifier = canvasModifier) {
drawIntoLayer {
drawPath(
path = rhombusPath,
lightnessGradient,
)
drawPath(
path = rhombusPath,
saturationHSLGradient,
blendMode = BlendMode.Overlay
)
}
}
混合绘图功能
fun DrawScope.drawIntoLayer(
content: DrawScope.() -> Unit
) {
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
content()
restoreToCount(checkPoint)
}
}
HSV 和 HSL 渐变的结果,小矩形不是用渐变绘制的,而是在点处绘制小矩形以验证 HSL 渐变与位置处的真实颜色匹配。
Github 完整实施的回购可用 here。