[英]How to achieve this layout in Jetpack Compose
I'm trying to use the new Jetpack Compose UI framework, but I'm running into an issue.我正在尝试使用新的 Jetpack Compose UI 框架,但遇到了问题。 I'd like to achieve this layout, which in xml is pretty easy to achieve:我想实现这种布局,在 xml 中很容易实现:
But I can't figure out how to make the vertical divider take up the available vertical space, without specifying a fixed height.但我不知道如何让垂直分隔线占用可用的垂直空间,而不指定固定高度。 This code that I've tried doesn't seem to work:我尝试过的这段代码似乎不起作用:
@Composable
fun ListItem(item: PlateUI.Plate) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp),
text = item.name
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
I keep getting this result:我不断得到这个结果:
I also tried with ConstraintLayout, but it still didn't work我也尝试过使用 ConstraintLayout,但还是不行
@Composable
fun ListItem(item: PlateUI.Plate) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
ConstraintLayout(
modifier = Modifier.fillMaxWidth(),
) {
val(column, divider, text) = createRefs()
Column(
modifier = Modifier
.padding(8.dp)
.constrainAs(column){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
},
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
.constrainAs(divider){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(column.end)
}
)
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp)
.constrainAs(text){
start.linkTo(divider.end)
end.linkTo(parent.end)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = item.name
)
}
}
}
But nothing seems to work.但似乎没有任何效果。 Is this a bug, a missing feature or am I just missing something?这是一个错误,一个缺失的功能还是我只是错过了什么?
EDIT: Apparently the real problem is that the divider doesn't know how to measure when the Surface doesn't have a fixed height, setting height equal to some number solves the issue, but then the view doesn't adapt to the content height anymore, so this can't be the solution编辑:显然,真正的问题是当 Surface 没有固定高度时分隔器不知道如何测量,将高度设置为某个数字可以解决问题,但是视图不适应内容高度不再,所以这不是解决方案
You can set Intrinsic.Max
for the preferredHeight
of the Row
, then set the Spacer
to fill max height.您可以为Row
的preferredHeight
设置Intrinsic.Max
,然后将Spacer
设置为填充最大高度。 You can read more on Intrinsic
s in this codelab section .您可以在此 codelab 部分中阅读有关Intrinsic
的更多信息。
@Composable
fun ListItem() {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
Row(
modifier = Modifier.fillMaxWidth().preferredHeight(IntrinsicSize.Max),
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = "2456")
}
Spacer(
modifier = Modifier
.preferredWidth(1.dp)
.fillMaxHeight()
.background(color = Color.Black.copy(0.12f))
)
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp),
text = "Some name"
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
With 1.0.0-beta02
you can apply:使用1.0.0-beta02
您可以申请:
.height(IntrinsicSize.Max)
to the Row
修改器.height(IntrinsicSize.Max)
到Row
.width(1.dp).fillMaxHeight()
to the Spacer
修饰符.width(1.dp).fillMaxHeight()
到Spacer
You can read more about the Intrinsic measurements here .您可以在此处阅读有关内在测量的更多信息。
Something like:就像是:
Row(
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max),
verticalAlignment = Alignment.CenterVertically
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
....
) {
Text(text = "....")
}
Spacer(
modifier = Modifier
.width(1.dp)
.fillMaxHeight()
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(...)
}
I've solved it using constraint layout:我已经使用约束布局解决了它:
Box(modifier = Modifier.padding(Dp(50f))) {
ConstraintLayout(
modifier = Modifier
.border(width = Dp(1f), color = Color.Black)
.fillMaxWidth()
) {
val (left, divider, right) = createRefs()
Column(
modifier = Modifier
.padding(horizontal = Dp(20f))
.constrainAs(left) {
width = Dimension.wrapContent
start.linkTo(parent.start)
top.linkTo(parent.top)
end.linkTo(divider.start)
bottom.linkTo(parent.bottom)
}
) {
Text(text = "Code")
Text(text = "A12")
}
Box(
modifier = Modifier
.width(Dp(1f))
.background(Color.Black)
.constrainAs(divider) {
width = Dimension.wrapContent
height = Dimension.fillToConstraints
start.linkTo(left.end)
top.linkTo(parent.top)
end.linkTo(right.start)
bottom.linkTo(parent.bottom)
}
)
Box(
modifier = Modifier
.constrainAs(right) {
width = Dimension.fillToConstraints
start.linkTo(divider.end)
top.linkTo(parent.top)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom)
}
) {
Text(
text = "Test",
modifier = Modifier
.padding(vertical = Dp(100f))
.align(Alignment.Center)
)
}
}
}
The key part is using that modifier height = Dimension.fillToConstraints
关键部分是使用修饰符height = Dimension.fillToConstraints
There are plenty of solutions here, but I thought I could demonstrate the ConstraintLayout approach and add a helpful usage of the IntrinsicSize
enum that solves one of the issues (needing an adaptive height for the composable).这里有很多解决方案,但我想我可以演示 ConstraintLayout 方法并添加IntrinsicSize
枚举的有用用法,以解决其中一个问题(需要一个可组合的自适应高度)。 Interestingly, either IntrinsicSize.Max
or IntrinsicSize.Min
will yield the desired behavior.有趣的是, IntrinsicSize.Max
或IntrinsicSize.Min
将产生所需的行为。
I used most of your code.我使用了你的大部分代码。 The key differences are:主要区别是:
.fillMaxHeight()
其他人已经提到,间隔修饰符应该包括.fillMaxHeight()
.height(IntrinsicSize.Min)
docs ref here: https://developer.android.com/jetpack/compose/layout#intrinsic-measurements将表面包装器的高度定义为.height(IntrinsicSize.Min)
文档参考: https : //developer.android.com/jetpack/compose/layout#intrinsic-measurementswidth
, instead of preferredWidth
必须更改 Spacer 修饰符才能访问width
,而不是preferredWidth
@Composable
fun ListItem(item: Plate) {
Surface(
modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Min),
shape = RoundedCornerShape(8.dp),
elevation = 2.dp
) {
ConstraintLayout(
modifier = Modifier.fillMaxWidth(),
) {
val guideline = createGuidelineFromStart(0.2f)
val(column, divider, text) = createRefs()
Column(
modifier = Modifier
.padding(8.dp)
.constrainAs(column){
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
end.linkTo(guideline)
},
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Code")
Text(text = item.code)
}
Spacer(
modifier = Modifier
.constrainAs(divider){
top.linkTo(column.top)
bottom.linkTo(column.bottom)
start.linkTo(guideline)
}
.width(1.dp)
.fillMaxHeight()
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 34.dp)
.constrainAs(text){
start.linkTo(divider.end)
end.linkTo(parent.end)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = item.name
)
}
}
}
I think Row layout is enough.我认为行布局就足够了。
@Preview(showBackground = true, heightDp = 100)
@Composable
fun ListItem(item: PlateUI.Plate = PlateUI.Plate()) {
Card(
shape = RoundedCornerShape(8.dp)
) {
Row(
modifier = Modifier
.fillMaxSize(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.padding(8.dp),
text = "Code\n${item.code}",
textAlign = TextAlign.Center
)
Box(
Modifier
.fillMaxHeight()
.width(1.dp)
.background(color = MaterialTheme.colors.onSurface.copy(0.12f))
)
Text(
modifier = Modifier
.weight(1f)
.padding(8.dp),
text = item.name,
textAlign = TextAlign.Center
)
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.