android - 如何使用 Jetpack Compose 创建 HSL 饱和度和亮度变化渐变或画笔编辑器?

标签 android android-jetpack-compose android-canvas android-jetpack-compose-canvas

我正在使用 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)
    }

我需要的是将第一张图像的颜色应用于右侧的类似菱形的图像,而无需绘制圆圈或路径。我认为这可以通过一个渐变或多个渐变或混合它们来解决,但不知道如何解决。

检查了这个question in c#供引用,但不知道如何将其应用到 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
    )
}

然后使用 Overlay 的 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渐变与位置处的真实颜色匹配。

enter image description here

可用于全面实现的 Github 存储库已可用 here .

关于android - 如何使用 Jetpack Compose 创建 HSL 饱和度和亮度变化渐变或画笔编辑器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71423294/

相关文章:

android - 在 Jetpack Compose 中使用 SnapFlingBehavior 时,如何捕捉到 LazyColumn 的初始索引?

android - SurfaceView 不会被重绘

java - 相对布局 android Loopable

android - 联系人游标中的列 data4 无效

java - 如何解决 Android Studio 中的 'readLines' 错误

android - 无法在 Jetpack Compose 中创建按钮

android - 如何在jetpack compose中的安全区域上绘画?

android - ImageView适合宽度,从顶部开始

java - Android 绘制路径未填满封闭区域

android - 如何在 Canvas 上的两点之间绘制弧线?