Jetpack Compose 是一个声明式 Ui,您可以使用带有 @Composable 注释的函数创建 Ui 组件,这与您创建 View 或 ViewGroup 实例的 View 系统不同,您可以使用您定义的 id 获取它以设置属性。在 Jetpack Compose 中,您将 Composable 的属性声明为函数的参数。
Modifier.layoutId 在您构建具有特定布局的自定义可组合项时使用,以计算子可组合项的尺寸和位置。
/**
* Retrieves the tag associated to a composable with the [Modifier.layoutId] modifier.
* For a parent data value to be returned by this property when not using the [Modifier.layoutId]
* modifier, the parent data value should implement the [LayoutIdParentData] interface.
*
* Example usage:
* @sample androidx.compose.ui.samples.LayoutTagChildrenUsage
*/
val Measurable.layoutId: Any?
get() = (parentData as? LayoutIdParentData)?.layoutId
总而言之,当您构建自定义布局时,它就像
@Composable
private fun MyLayout(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Layout(
modifier = modifier,
content = content
) { measurables: List<Measurable>, constraints: Constraints ->
val placeables: List<Placeable> = measurables.map { measurable: Measurable ->
measurable.measure(constraints)
}
// Width and height of parent composable depends on requirements
layout(constraints.maxWidth, constraints.maxHeight) {
placeables.forEach { placeable: Placeable ->
// place composables based on requirements vertically, horizontally, diagonal, etc.
}
}
}
}
1- 您创建一个布局,它需要一个我们用 lambda 设置的 MeasurePolicy,并通过 layout(width, height) 函数返回 MeasureResult。
2- 约束是由大小修改器、滚动修改器或父级选择限制大小的方式设置的限制。 In Constraints section 我解释了哪个修饰符返回哪个绑定。您只能在这些范围内测量可测量的。
但是,如果您不让 Composable 通过 constraints.copy() 或 Constraints.fixed()、constraints.offset() 选择不同的边界,则可以修改 Constraints。一件重要的事情最大界限仍然在父母的最大界限内。
然后你只测量一次你的可测量,如果你再次尝试测量你会得到一个例外.
但是,有时您需要根据另一个 Composable 设置 Comosable 的尺寸。例如,如果 Image 是在运行时设置的 100.dp,而您希望将 Text 调整为 100.dp,并且您不知道在内容中设置了哪个顺序 Image 或 Text。
您需要使用 SubcomposeLayout,它使用 subcompose 函数来重新测量可组合项,或者您可以使用 Modifier.layoutId 来确定您首先测量的可组合项,如下面的示例或此答案的 Selectively measuring to match one Sibling to Another section 中所示
@Composable
private fun MyLayout(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Layout(
modifier = modifier,
content = content
) { measurables: List<Measurable>, constraints: Constraints ->
val imageMeasurable: Measurable = measurables.find { it.layoutId == "image" }!!
val textMeasurable: Measurable = measurables.find { it.layoutId == "text" }!!
val imagePlaceable = imageMeasurable.measure(constraints.copy(minWidth = 0, minHeight = 0))
// Limit text width to image width by setting min and max width at image width
val textPlaceable = textMeasurable.measure(
constraints.copy(
minWidth = imagePlaceable.width,
maxWidth = imagePlaceable.width
)
)
val width = imagePlaceable.width
val imagePlaceableHeight = imagePlaceable.height
val height = imagePlaceableHeight + textPlaceable.height
// Width and height of parent composable depends on requirements
layout(width, height) {
imagePlaceable.placeRelative(0, 0)
textPlaceable.placeRelative(0, imagePlaceableHeight)
}
}
}
示范
MyLayout(
modifier = Modifier
.fillMaxWidth()
.border(1.dp, Color.Cyan)
) {
Image(
modifier = Modifier
.size(150.dp)
.layoutId("image"),
painter = painterResource(id = R.drawable.landscape1),
contentDescription = null,
contentScale = ContentScale.FillBounds
)
Text(
modifier = Modifier
.layoutId("text")
.border(2.dp, Color.Red),
text = "Hello world some very long text that will be scaled"
)
}
MyLayout(
modifier = Modifier
.fillMaxWidth()
.border(1.dp, Color.Cyan)
) {
Text(
modifier = Modifier
.layoutId("text")
.border(2.dp, Color.Red),
text = "Hello world some very long text that will be scaled"
)
Image(
modifier = Modifier
.size(100.dp)
.layoutId("image"),
painter = painterResource(id = R.drawable.landscape1),
contentDescription = null,
contentScale = ContentScale.FillBounds
)
}
结果
如图所示,我们首先使用 layoutId 获取 Image,然后测量 Text 以使其宽度与 Image 匹配。我认为这不适用于 appium,除非它有某种检查员 Modifier