在 Jetpack Compose 中重组 Canvas

Recomposition of Canvas in Jetpack Compose

我正在使用 Jetpack Compose 来实现我绘制 'Gradual growing line' 的要求,即从指定起点和点开始并逐渐 'grows' 直到到达指定终点的线。 我早些时候用自定义视图实现了这个,效果很好。我的逻辑要求 'onDraw()' 根据某些条件一次又一次地重新调用。为此,我在使用自定义视图时使用了 'invalidate()'。但是现在我正在使用 Jetpack Compose 并且无法找到重组的方法 'Canvas'.

这是我的 'gradual growing line' 的 Jetpack 组合代码:

   @Composable
        fun SplashUI() {
            var test = remember { mutableStateOf(0) }
                Canvas(modifier = Modifier.fillMaxSize()) {
                    //  starting point
                    x1 = 0.0;
                    y1 = size.height / 2.0;

                    //  ending point
                    x2 = size.width.toDouble()
                    y2 = size.height / 2.0;

                    divideLineIntoEqualParts();

                    if (test.value < listOfPoints.size) {
                        drawLine(
                            Color.Black,
                            Offset(
                                listOfPoints.get(0)?.x!!,
                                listOfPoints.get(0)?.y!!
                            ),
                            Offset(
                                listOfPoints.get(inte)?.x!!,
                                listOfPoints.get(inte)?.y!!
                            ),
                            strokeWidth = 5f
                        );
                    }
                    test.value = test.value + 1 //This doesn't trigger recomposition of canvas
                    //Recomposition of Canvas should happen after the above step for my logic to work

                   //I had implemented this earlier using custom view, and used 'invalidate()' like:
                   /* if (inte < listOfPoints.size) {
                        invalidate()
                    }*/
            }
        }


    private fun divideLineIntoEqualParts() {
        listOfPoints.clear()
        for (k in 1..50) {
            listOfPoints.add(PointF((x1 + k * (x2 - x1) / 50).toFloat(),
                (y1 + k * (y2 - y1) / 50).toFloat()
            ))
        }
        Log.d("listOfPoints : size : ", listOfPoints.size.toString() + "")
    }

请建议我可以重组 Canvas 的方法,或者让我的逻辑正常工作的其他方法。

有些不同。
问题中的代码在 Android View 中工作,并且您正在 onDraw 方法中利用 Canvas 。您正在绘制一条水平线,以点为单位划分可用 space(=宽度)。

在 Compose 中,您只是将 Canvas 用作 Composable,并且可以为线条的长度设置动画。 类似于:

//Animation - it will be repeated 2 times
val animatedProgress = remember { Animatable(0.001f) }
LaunchedEffect(animatedProgress) {
    animatedProgress.animateTo(1f,
        animationSpec = repeatable(2,
            animation = tween(durationMillis = 3000, easing = LinearEasing)
        ))
}

Canvas(modifier = Modifier.fillMaxSize() ) {

    val startingPoint = Offset(0f, size.height / 2f)
    val endingPoint = Offset(size.width * animatedProgress.value, size.height / 2f)

    //At the end of animation just remove the line
    if (animatedProgress.isRunning) {
        drawLine(
            strokeWidth = 8.dp.toPx(),
            color = Color.Black,
            start = startingPoint,
            end = endingPoint
        )
    }
}

我同意 Gabriele Mariotti 的回答,但我发现有时您需要控件以便能够在 canvas 中随时重绘!

我正在尝试开发一个绘图应用程序,当触摸事件发生时我必须使它无效!

在这篇文章中 Simple Jetpack Drawing App canvas 因 MotionEvent 动作的变化而失效,因此每次运动事件的动作发生变化时 canvas 都可以失效(重绘)

我们可以使用相同的逻辑

var invalidations by remember{
    mutableStateOf(0)
}

现在 Canvas 可组合

Canvas {
    invalidations.let{inv->
        //Draw Composables
    }
}

现在只要你想使它无效:

invalidations++

这不是执行此操作的最佳方法,因为更改一个变量的状态只会导致重绘该可组合项,但以这种方式无效将重绘在 invalidations.let 块内绘制的任何内容!