簡體   English   中英

如何使用 Jetpack Compose Canvas 與動態大小的布局

[英]How to use Jetpack Compose Canvas with Layout with dynamic size

I want to set androidx.compose.foundation.Canvas size dynamically after measuring measurables and placing placeables with layout function but Canvas requires a Modifier with specific size how can achieve this with Layout and Canvas and in efficient way.

在此處輸入圖像描述

我想要實現的是在圖像中設置內容並添加一些空間並在紅色區域繪制箭頭以創建語音氣泡,如此處所示

圖像中的第一個容器是正確的,其中 Modifier.layout 和 Modifier.drawbackground 為

@Composable
private fun MyComposable(modifier: Modifier = Modifier) {

    Row(
        modifier = Modifier

    ) {
        var totalSize = Size.Zero

        val layoutModifier = modifier
            .layout { measurable, constraints ->

                val placeable = measurable.measure(constraints)
                totalSize = Size(placeable.width + 50f, placeable.height.toFloat())

                println("MyComposable() LAYOUT placeable: $placeable")

                layout(totalSize.width.roundToInt(), placeable.height) {
                    placeable.place(0, 0)
                }

            }
            .drawBehind {
                println("MyComposable() drawBehind size: $size")
                drawRect(Color.Red, size = totalSize, style = Stroke(2f))
                drawRect(Color.Blue, size = size, style = Stroke(2f))
            }


        Column(modifier = layoutModifier) {
            Text("First Text")
            Text("Second Text")
        }

    }
}

和日志

I: MyComposable() LAYOUT placeable width: 250, height: 124
I: MyComposable() drawBehind size: Size(250.0, 124.0)

帶布局和 Canvas

@Composable
private fun CanvasLayout(modifier: Modifier = Modifier, content: @Composable () -> Unit) {

    var widthInDp by remember { mutableStateOf(0.dp) }
    var heightInDp by remember { mutableStateOf(0.dp) }

    Layout(content = content, modifier = modifier) { measurables, constraints ->

        val placeables = measurables.map { measurable ->
            measurable.measure(constraints)
        }

        val maxWidth = placeables.maxOf { it.width } + 50
        val height = placeables.sumOf { it.height }

        widthInDp = (maxWidth / density).toDp()
        heightInDp = (height / density).toDp()
        println("🚗 CanvasLayout() LAYOUT maxWidth: $maxWidth, height: $height placeables: ${placeables.size}")

        var yPos = 0
        layout(maxWidth, height) {
            placeables.forEach { placeable: Placeable ->
                placeable.placeRelative(0, yPos)
                yPos += placeable.height
            }
        }
    }

    androidx.compose.foundation.Canvas(
        modifier = Modifier.size(widthInDp, heightInDp),
        onDraw = {
            println("🚙 CanvasLayout() CANVAS size: $size")
            drawRect(Color.Blue, size = size, style = Stroke(2f))
        }
    )
}

從圖像中可以看出,底部矩形繪制在 Text composables 下方而不是圍繞它們並調用layout兩次

I: 🚗 CanvasLayout() LAYOUT maxWidth: 300, height: 124 placeables: 2
I: 🚙 CanvasLayout() CANVAS size: Size(0.0, 0.0)
I: 🚗 CanvasLayout() LAYOUT maxWidth: 300, height: 124 placeables: 2
I: 🚙 CanvasLayout() CANVAS size: Size(114.0, 47.0)

一起使用LayoutCanvas正確有效方法是什么?

有時它需要一個動態大小,這需要您修改 Canvas 大小,就像這個問題一樣。

由於CanvasSpacer

@Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit) =
    Spacer(modifier.drawBehind(onDraw))

畫在后面工作正常。

但有時您使用 Canvas 設計布局,canvas 恰好位於底層的無狀態可組合中,例如默認的 Slider 源代碼。

fun Slider() {
   // States rememberables
  SliderImpl()
}

fun SliderImpl() {
   Canvas()
   // Other Composables like thumb
}

當您需要將動態大小傳遞給 Canvas 時,選項很少

1- 在您想要獲取尺寸的布局上使用 Modifier.onSizeChanged{},但不建議這樣做,它可能會導致您設置大小並再次讀取的無限循環

2- 使用返回 min/maxWidth、min/maxHeight 但最大約束的BoxWithConstraints並不總是對應於布局的邊界。 當使用 Modifier.fillMax 或您具有固定大小時,當您的 Composable 填充整個布局時,它會起作用。

3- 其他選項是使用SubcomposeLayout ,您可以在其中創建主要(您想要測量)和依賴(您想要將測量傳遞給)可組合項。 主要組件被子組合並將維度傳遞給依賴的組件,然后您對其進行設置。

ScaffoldTabRow使用此邏輯來測量和空間基於其他的可組合。 您可以查看有關 SubcomposeLayout 的此鏈接以獲取更多詳細信息。 BoxWithConstraintsLazyList也是 SubcomposeLayouts

4- LookAheadLayout ,這也可能有效,我還沒有嘗試過,當我這樣做時,我將使用示例編輯此答案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM