Как добиться такого макета в Jetpack Compose

#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
            )
        }
    }
}
  

Предварительный просмотр элементов списка