#android #android-layout #android-jetpack-compose
#Android #android-макет #android-jetpack-compose
Вопрос:
Я пытаюсь использовать новую платформу пользовательского интерфейса Jetpack Compose, но у меня возникла проблема. Я бы хотел добиться такого макета, которого в xml довольно легко достичь:
Но я не могу понять, как заставить вертикальный разделитель занимать доступное вертикальное пространство, не указывая фиксированную высоту. Этот код, который я пробовал, похоже, не работает:
@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))
}
}
}
Я продолжаю получать этот результат:
Я также пробовал с 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
)
}
}
}
Но, похоже, ничего не работает. Это ошибка, недостающая функция или я просто что-то упускаю?
РЕДАКТИРОВАТЬ: По-видимому, реальная проблема заключается в том, что разделитель не знает, как измерять, когда поверхность не имеет фиксированной высоты, установка высоты, равной некоторому числу, решает проблему, но тогда представление больше не адаптируется к высоте содержимого, поэтому это не может быть решением
Ответ №1:
Вы можете применить:
- модификатор
.height(IntrinsicSize.Max)
дляRow
- модификаторы
.width(1.dp).fillMaxHeight()
кSpacer
Вы можете прочитать больше о внутренних измерениях здесь .
Что-то вроде:
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(...)
}
Комментарии:
1. Хорошо, по-видимому, проблема возникает, когда вы размещаете вертикальный разделитель внутри поверхности, которая не имеет статически определенной высоты, а вместо этого основана на высоте ее содержимого.
2. сначала вы можете определить высоту строки с помощью модификатора. высота (200.dp), например, затем в разделителе (Modifier.fillMaxHeight()).
3. Ну … нет. Таким образом, строка не будет иметь динамической высоты, я хочу, чтобы она адаптировалась к нескольким строкам текста и другим изменениям высоты
Ответ №2:
Вы можете установить Intrinsic.Max
для preferredHeight
Row
, затем установить Spacer
для заполнения максимальной высоты. Вы можете прочитать больше о Intrinsic
s в этом разделе codelab.
@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))
}
}
}
Ответ №3:
Я решил это с помощью компоновки ограничений:
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)
)
}
}
}
Ключевой частью является использование этого модификатора height = Dimension.fillToConstraints
Ответ №4:
Здесь есть много решений, но я подумал, что мог бы продемонстрировать подход ConstraintLayout и добавить полезное использование IntrinsicSize
enum, которое решает одну из проблем (требуется адаптивная высота для компоновки). Интересно, что либо IntrinsicSize.Max
или IntrinsicSize.Min
приведет к желаемому поведению.
Я использовал большую часть вашего кода. Ключевыми отличиями являются:
- объявляет руководство (мое значение, переданное для дроби, не дает точного результата, который вы искали, но его можно легко настроить (используйте дробь немного меньше.2) Это может быть полезно, если вы ожидаете, что wrapContent изменит ваш левый текст, чтобы изменить расположение разделителя, но предпочел бы согласованное расположение разделителя в списке этих элементов.
- другие упоминали, что модификатор spacer должен включать
.fillMaxHeight()
- определите высоту оболочки поверхности, которая будет указана в
.height(IntrinsicSize.Min)
документах здесь: https://developer.android.com/jetpack/compose/layout#intrinsic-measurements - запуск разделителя ограничен руководством
- пришлось изменить модификатор 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
)
}
}
}
Ответ №5:
Я думаю, что компоновки строк достаточно.
@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 = "Coden${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
)
}
}
}