如何使用 Modifier 镜像 canvas 制作的可组合函数?

2023-12-29

问题描述

我正在尝试使用 Compose 和 Canvas 在 android 上创建一个模拟 7 段显示的组件,如下所示:

为此,我采取了仅创建该组件的一半并向下镜像我创建的这部分的策略,所以我会拥有整个显示。

这是 7 段显示屏的顶部部分:

但问题是何时“镜像”从上到下。事实证明,当我添加Modifier.rotate(180f)该图形围绕画布的原点顺时针旋转,因此它不会出现在屏幕上(如果逆时针旋转,则会出现在屏幕上)。

我不想使用字体来解决这个问题,我想通过画布解决这个问题并自行组合。如果有一种更聪明的方法可以在画布上做到这一点,而不必需要镜子,我想知道。

My code

下面是我用来绘制此图的代码:

显示组件.kt

@Composable
fun DisplayComponent(
    modifier: Modifier = Modifier,
    size: Int = 1000,
    color: Color = MaterialTheme.colors.primary,
) {
    Column(modifier = modifier) {
        HalfDisplayComponent(size, color)
        HalfDisplayComponent(
            modifier = Modifier.rotate(180f),
            size = size,
            color = color
        )
    }
}

@Composable
private fun HalfDisplayComponent(
    size: Int,
    color: Color,
    modifier: Modifier = Modifier,
) {
    Box(modifier = modifier) {
        LedModel.values().forEach {
            LedComponent(
                ledModel = it,
                size = size,
                color = color
            )
        }
    }
}

LedModel.kt

enum class LedModel(val coordinates: List<Pair<Float, Float>>) {
    HorizontalTop(
        listOf(
            Pair(0.04f, 0.03f), // Point A
            Pair(0.07f, 0f), // Point B
            Pair(0.37f, 0f), // Point C
            Pair(0.4f, 0.03f), // Point D
            Pair(0.34f, 0.08f), // Point E
            Pair(0.1f, 0.08f), // Point F
        )
    ),
    VerticalRight(
        listOf(
            Pair(0.41f, 0.04f), // Point A
            Pair(0.44f, 0.07f), // Point B
            Pair(0.44f, 0.37f), // Point C
            Pair(0.41f, 0.4f), // Point D
            Pair(0.35f, 0.35f), // Point E
            Pair(0.35f, 0.09f), // Point F
        )
    ),
    VerticalLeft(
        listOf(
            Pair(0.03f, 0.4f), // Point A
            Pair(0f, 0.37f), // Point B
            Pair(0f, 0.07f), // Point C
            Pair(0.03f, 0.04f), // Point D
            Pair(0.09f, 0.09f), // Point E
            Pair(0.09f, 0.35f), // Point F
        )
    ),
    HorizontalBottom(
        listOf(
            Pair(0.1f, 0.36f), // Point A
            Pair(0.34f, 0.36f), // Point B
            Pair(0.39f, 0.4f), // Point C
            Pair(0.05f, 0.4f), // Point D
        )
    ),
}

LedComponent.kt

@Composable
fun LedComponent(
    modifier: Modifier = Modifier,
    size: Int = 30,
    color: Color = MaterialTheme.colors.primary,
    ledModel: LedModel = LedModel.HorizontalTop
) = getPath(ledModel.coordinates).let { path ->
    Canvas(modifier = modifier.scale(size.toFloat())) {
        drawPath(path, color)
    }
}

private fun getPath(coordinates: List<Pair<Float, Float>>): Path = Path().apply {
    coordinates.map {
        transformPointCoordinate(it)
    }.forEachIndexed { index, point ->
        if (index == 0) moveTo(point.x, point.y) else lineTo(point.x, point.y)
    }
}

private fun transformPointCoordinate(point: Pair<Float, Float>) =
    Offset(point.first.dp.value, point.second.dp.value)

我失败的尝试

如前所述,我尝试添加Modifier通过旋转显示器的可组合项,但它没用。我是这样做的:

@Composable
fun DisplayComponent(
    modifier: Modifier = Modifier,
    size: Int = 1000,
    color: Color = MaterialTheme.colors.primary,
) {
    Column(modifier = modifier) {
        DisplayFABGComponent(size, color)
        DisplayFABGComponent(
            modifier = Modifier.rotate(180f),
            size = size,
            color = color
        )
    }
}

您上面发布的代码有很多问题。

首先,在 Jetpack Compose 中,即使您的 Canvas 大小为 0.dp,您仍然可以在任何地方绘制,这是您问题中的第一个问题。您的画布没有尺寸修改器,您可以通过打印来验证DrawScope.size如下。

fun LedComponent(
    modifier: Modifier = Modifier,
    size: Int = 1000,
    color: Color = MaterialTheme.colorScheme.primary,
    ledModel: LedModel = LedModel.HorizontalTop
) = getPath(ledModel.coordinates).let { path ->
    Canvas(
        modifier = modifier.scale(size.toFloat())
    ) {

        println("CANVAS size: ${this.size}")
        drawPath(path, color)
    }
}

您输入的任何值都没有区别,除了Modifier.scale(0f),这也不是您应该如何构建或缩放绘图的方式。

如果您为画布设置尺寸,例如

@Composable
fun DisplayComponent(
    modifier: Modifier = Modifier,
    size: Int = 1000,
    color: Color = MaterialTheme.colorScheme.primary,
) {
    Column(modifier = modifier) {
        HalfDisplayComponent(
            size,
            color,
            Modifier
                .size(200.dp)
                .border(2.dp,Color.Red)
        )
        HalfDisplayComponent(
            modifier = Modifier
                .size(200.dp)
                .border(2.dp, Color.Cyan)
                .rotate(180f),
            size = size,
            color = color
        )
    }
}

旋转有效,但您绘制的内容与问题中的图像不对称。

point.first.dp.value这个片段什么也不做。它的作用是将 dp 添加到 float,然后获得 float。这不是进行 float/dp 转换的方式,也没有必要。

您可以通过以下方式实现您的目标一张画布或使用 Modifier.drawBehind{}。使用尺寸作为半组件的参考创建路径,然后再次绘制并旋转它或创建包含完整 LED 组件的路径。或者,如果您希望单独显示 LED 数字,则可以为每个部分设置路径。

这是一个简单的示例,仅构建一个菱形形状,然后平移并旋转它以使用半组件构建沙漏状形状。您可以使用此示例作为演示如何使用大小作为参考来创建路径、平移和旋转。

fun getHalfPath(path: Path, size: Size) {
    path.apply {
        val width = size.width
        val height = size.height / 2
        moveTo(width * 0f, height * .5f)
        lineTo(width * .3f, height * 0.3f)
        lineTo(width * .7f, height * 0.3f)
        lineTo(width * 1f, height * .5f)
        lineTo(width * .5f, height * 1f)
        lineTo(width * 0f, height * .5f)
    }
}

您需要使用 1/2f 的纵横比才能进行对称绘图。绿色边框显示 Box 可组合项的边界。

val path = remember {
    Path()
}

Box(modifier = Modifier
    .border(3.dp, Color.Green)
    .fillMaxWidth(.4f)
    .aspectRatio(1 / 2f)
    .drawBehind {
        if (path.isEmpty) {
            getHalfPath(path, size)
        }

        drawPath(
            path = path,
            color = Color.Red,
            style = Stroke(2.dp.toPx())
        )

        withTransform(
            {
                translate(0f, size.height / 2f)
                rotate(
                    degrees = 180f,
                    pivot = Offset(center.x, center.y / 2)
                )
            }
        ) {
            drawPath(
                path = path,
                color = Color.Black,
                style = Stroke(2.dp.toPx())
            )
        }
    }

Result

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Modifier 镜像 canvas 制作的可组合函数? 的相关文章

随机推荐