代码之家  ›  专栏  ›  技术社区  ›  tickstop

Jetpack Compose-将布局的子元素扩展到边界之外

  •  1
  • tickstop  · 技术社区  · 6 月前

    我正在寻找一种方法,使布局元素(行或列)的子元素在垂直方向上超出其父元素的边界。我想这样做是因为我想让背景中的行有一个颜色集,但子元素的周围区域是透明的。

    以下是我想要实现的视觉表示:(想发布一张图片,但我还没有足够的声誉)

      -------
      |     | <- extended element
      |     |
    --|     |----------
    | |     |         | <- row with background
    | -------         |
    -------------------
    

    理想情况下,假设的一行父母应该尊重延伸孩子的身高。这是因为,据我所知,扩展部分通常会被其上方的其他组件切断,或者被屏幕边缘切断(因为它超出了界限)。

    我已经试过两件事了

    使用全球定位

    使用此方法,可能有某种方法,但我没有找到使用LayoutCoordinates lambda参数提供的位置方法的方法。

    此外,我观察到子元素在第一次构图后会“跳跃”。如果可能的话,我想避免这种情况。

    使用中描述的方法 this answer

    有了这个,我可以更改子元素的位置以及行本身,但调整大小似乎不起作用。

    也许我在某个地方做错了什么,但这就是我现在得到的:

    val itemWidth = 128
    val itemHeight = 256
    
    Row(
        modifier = Modifier.fillMaxWidth()
    ) {
        Box(
            modifier = Modifier
                .width(itemWidth.dp)
                .layout { measurable, constraints ->
                    val placeable = measurable.measure(
                        constraints.copy(
                            maxHeight = itemHeight.dp.roundToPx()
                        )
                    )
                    layout(
                        placeable.width,
                        placeable.height
                    ) {
                        placeable.place(0, 0)
                    }
                }
                .background(color = Color.Blue)
            )
            Text(
                text = "This is text filling the rest of the row",
                modifier = Modifier
                    .weight(1f)
                    .padding(8.dp)
            )
        }
    }
    
    1 回复  |  直到 6 月前
        1
  •  1
  •   Thracian    6 月前

    Constraints 是一个范围,用于衡量可测量的组成部分。如果未设置minheight,则它来自父级或以前的尺寸约束。如果它是0,那么你的Composable将在0和256.dp像素值之间进行测量,因为你需要将minHeight设置为与maxHeight相同的值,以便用固定高度而不是在一个范围内进行测量。假设内容为30.dp,并且以0-100.dp的范围进行测量,则从不为其分配100.dp的高度。

    此外,设置placeable.place(0,yPos)和低于0的yPos将使其位于行中定义的位置之上。

    最后,如果你不给父行分配hight,它将得到子行的高度,最大高度为 Box 使用布局修改器。

    val itemWidth = 128
    val itemHeight = 256
    
    @Preview
    @Composable
    fun LayoutTest() {
        Column(
            modifier = Modifier.fillMaxSize()
        ) {
            Row(
                modifier = Modifier
                    .padding(top = 300.dp)
                    .fillMaxWidth()
                    .height(50.dp)
                    .border(2.dp, Color.Red)
            ) {
                Box(
                    modifier = Modifier
                        .width(itemWidth.dp)
                        .layout { measurable, constraints ->
                            val placeable = measurable.measure(
                                constraints.copy(
                                    minHeight = itemHeight.dp.roundToPx(),
                                    maxHeight = itemHeight.dp.roundToPx()
                                )
                            )
                            layout(
                                placeable.width,
                                placeable.height
                            ) {
                                placeable.placeRelative(0, 0)
                            }
                        }
                        .background(color = Color.Blue)
                        .border(2.dp, Color.Green)
    
                )
                Text(
                    text = "This is text filling the rest of the row",
                    modifier = Modifier
                        .weight(1f)
                        .padding(8.dp)
                )
            }
        }
    }
    

    结果如下

    enter image description here

    蓝色框居中的原因是它不遵守父约束,因为父约束试图将其居中。您可以参考 this answer 有关更多详细信息,但一般来说,如果测量值不在父约束或先前修改器约束的范围内,则无论其大小,可组合的约束都是居中的。

    为了克服这一点,你需要用以下方式抵消两者的差异

    val userOffset = 0
    placeable.placeRelative(
        x = 0,
        y = (constraints.maxHeight - placeable.height) / 2 + userOffset
    )
    

    将结果

    enter image description here

    如果为userOffset设置负值,蓝色框将放置在更靠近顶部的位置。