簡體   English   中英

獲取元素的高度 Jetpack Compose

[英]Get height of element Jetpack Compose

我想在 Jetpack Compose 中獲取按鈕(或其他元素)的高度。 你知道怎么得到嗎?

如果您想在合成后獲得按鈕的高度,則可以使用: onGloballyPositionedModifier

它返回一個 LayoutCoordinates object,其中包含按鈕的大小。

一個完整的解決方案如下:

@Composable
fun GetHeightCompose() {
    // get local density from composable
    val localDensity = LocalDensity.current
    var heightIs by remember {
        mutableStateOf(0.dp)
    }
    Box(modifier = Modifier.fillMaxSize()) {
        // Important column should not be inside a Surface in order to be measured correctly
        Column(
            Modifier
                .onGloballyPositioned { coordinates ->
                    heightIs = with(localDensity) { coordinates.size.height.toDp() }
                }) {
            Text(text = "If you want to know the height of this column with text and button in Dp it is: $heightIs")
            Button(onClick = { /*TODO*/ }) {
                Text(text = "Random Button")
            }
        }
    }
}

您還可以使用BoxWithConstraints ,如下所示:

Button(onClick = {}){

   BoxWithConstraints{
     val height = maxHeight

   }
}

但我不確定它是否適合您的特定用例。

Modifier.onSizeChanged{}Modifier.globallyPositioned{}與 remember 和 mutableStateOf 一起使用需要另一個組合,並且根據您對這些值所做的操作,它可能會導致值跳轉。

例如

Column {

    var sizeInDp by remember { mutableStateOf(DpSize.Zero) }
    val density = LocalDensity.current

    // In practice we don't know this size, it's for demonstration
    Box(modifier = Modifier
        .onSizeChanged {
            sizeInDp = density.run {
                DpSize(
                    it.width.toDp(),
                    it.height.toDp()
                )
            }
        }
        .size(200.dp)
        .background(Color.Red))

    Text(
        "Hello World",
        modifier = Modifier
            .background(Color.White)
            .size(sizeInDp)
    )
}

文本的背景將從初始背景移動到下一次重組時的 200.dp 大小。 如果您正在執行更改任何 UI 繪圖的操作,用戶可能會注意到它是 flash 或故障。

在不重新組合的情況下獲取元素高度的第一個替代方法是使用BoxWithConstraints

BoxWithConstraints ' BoxScope包含 dp 中的maxHeight和 Int 中的constraints.maxHeigh t。

但是 BoxWithConstraints 在某些條件下(例如使用 Modifier.fillMaxHeight、沒有任何大小修飾符或具有垂直滾動的父級返回不正確的值)返回的約束不是精確的大小

您可以查看有關從 BoxWithConstraints 返回的尺寸的答案,Constraints 部分顯示了使用 BoxWithConstraints 將獲得什么。

verticalScroll 返回 Constraints.Infinity 作為高度。

獲得精確尺寸的可靠方法是使用 SubcomposeLayout

如何在不重新組合的情況下獲得准確的尺寸?

**
 * SubcomposeLayout that [SubcomposeMeasureScope.subcompose]s [mainContent]
 * and gets total size of [mainContent] and passes this size to [dependentContent].
 * This layout passes exact size of content unlike
 * BoxWithConstraints which returns [Constraints] that doesn't match Composable dimensions under
 * some circumstances
 *
 * @param placeMainContent when set to true places main content. Set this flag to false
 * when dimensions of content is required for inside [mainContent]. Just measure it then pass
 * its dimensions to any child composable
 *
 * @param mainContent Composable is used for calculating size and pass it
 * to Composables that depend on it
 *
 * @param dependentContent Composable requires dimensions of [mainContent] to set its size.
 * One example for this is overlay over Composable that should match [mainContent] size.
 *
 */
@Composable
fun DimensionSubcomposeLayout(
    modifier: Modifier = Modifier,
    placeMainContent: Boolean = true,
    mainContent: @Composable () -> Unit,
    dependentContent: @Composable (Size) -> Unit
) {
    SubcomposeLayout(
        modifier = modifier
    ) { constraints: Constraints ->

        // Subcompose(compose only a section) main content and get Placeable
        val mainPlaceables: List<Placeable> = subcompose(SlotsEnum.Main, mainContent)
            .map {
                it.measure(constraints.copy(minWidth = 0, minHeight = 0))
            }

        // Get max width and height of main component
        var maxWidth = 0
        var maxHeight = 0

        mainPlaceables.forEach { placeable: Placeable ->
            maxWidth += placeable.width
            maxHeight = placeable.height
        }

        val dependentPlaceables: List<Placeable> = subcompose(SlotsEnum.Dependent) {
            dependentContent(Size(maxWidth.toFloat(), maxHeight.toFloat()))
        }
            .map { measurable: Measurable ->
                measurable.measure(constraints)
            }


        layout(maxWidth, maxHeight) {

            if (placeMainContent) {
                mainPlaceables.forEach { placeable: Placeable ->
                    placeable.placeRelative(0, 0)
                }
            }

            dependentPlaceables.forEach { placeable: Placeable ->
                placeable.placeRelative(0, 0)
            }
        }
    }
}

enum class SlotsEnum { Main, Dependent }

用法

val content = @Composable {
    Box(
        modifier = Modifier
            .size(200.dp)
            .background(Color.Red)
    )
}

val density = LocalDensity.current

DimensionSubcomposeLayout(
    mainContent = { content() },
    dependentContent = { size: Size ->
        content()
        val dpSize = density.run {size.toDpSize() }
        Box(Modifier.size(dpSize).border(3.dp, Color.Green))
    },
    placeMainContent = false
)

或者

DimensionSubcomposeLayout(
    mainContent = { content() },
    dependentContent = { size: Size ->
        val dpSize = density.run {size.toDpSize() }
        Box(Modifier.size(dpSize).border(3.dp, Color.Green))
    }
)

在使用Modifier.onSizeChanged時,我設法實施了一種變通方法,通過使從中讀取的可組合對象成為無狀態的,從而減少(不是完全移除)重組次數。 不是可用的最佳方法,但它可以完成工作。

@Composable
fun TextToMeasure(
    currentHeight: Dp,
    onHeightChanged: (Dp) -> Unit,
    modifier: Modifier = Modifier,
) {
    val density = LocalDensity.current

    Text(
        text = "Hello Android",
        modifier = modifier
            .onSizeChanged { size ->
                val newHeight = with(density) { size.height.toDp }
                
                if (newHeight != currentHeight) {
                    onHeightChanged(newHeight)
                }
            },
    )
}

@Composable
fun MainScreen() {
    val height = remember { mutableStateOf(0.dp) }

    TextToMeasure(
        currentHeight = height.value,
        onHeightChanged = { height.value = it },
    )
}

暫無
暫無

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

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