Как создать карту с ленивым вертикальным списком элементов, которые могут быть вложены в прокручиваемый столбец с помощью Compose?

Я хотел бы иметь Compose UI, что-то вроде этого (слишком упрощенная версия)...

Каждый карточный список под каждой группой имеет переменную длину в зависимости от списка элементов, подаваемых на компоновку. Вот два варианта того, как подойти к этому (используя a или ):

      @Composable
fun CardedColumn(items: ImmutableList<String>) {
    Card(modifier = Modifier.fillMaxWidth().wrapContentHeight().padding(8.dp)) {
        Column {
            items.forEach { text: String ->
                Text(text = text, modifier = Modifier.padding(8.dp))
                Divider(modifier = Modifier.fillMaxWidth())
            }
        }
    }
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun CardedLazyColumn(items: ImmutableList<String>) {
    Card(modifier = Modifier.fillMaxWidth().wrapContentHeight().padding(8.dp).animateContentSize()) {
        LazyColumn {
            items(items = items, key = { it }) { text: String ->
                Text(text = text, modifier = Modifier.padding(8.dp).animateItemPlacement())
                Divider(modifier = Modifier.fillMaxWidth())
            }
        }
    }
}

//================================================================================
// Previews
//================================================================================
@Preview(widthDp = 320, heightDp = 320)
@Composable
fun CardedLazyColumn_Preview() {
    Column {
        val showItems = remember { mutableStateOf(true) }
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text("Show items: ")
            Switch(checked = showItems.value, onCheckedChange = { showItems.value = it })
        }
        CardedLazyColumn(getItems(showItems.value))
    }
}

@Preview(widthDp = 320, heightDp = 320)
@Composable
fun CardedColumn_Preview() {
    Column {
        val showItems = remember { mutableStateOf(true) }
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text("Show items: ")
            Switch(checked = showItems.value, onCheckedChange = { showItems.value = it })
        }
        CardedColumn(getItems(showItems.value))
    }
}

//================================================================================
// Helper Functions
//================================================================================
/**
 * Helper function to get more or less items depending upon [showMoreItems] argument
 */
private fun getItems(showMoreItems: Boolean): ImmutableList<String> {
    return if(showMoreItems) {
        persistentListOf("Lorem", "ipsum", "dolor", "sit", "amet")
    } else {
        persistentListOf("Lorem", "dolor", "sit", "amet")
    }
}

Если вы попробуете оба предварительных просмотра в интерактивном режиме или в Run Preview , вы заметите, чтоCardedLazyColumnанимирует отображение/скрытие новых элементов во времяCardedColumnне. Это связано с использованиемitem keyв комбинации сanimateContentItemPlacement, который запекается в анимации. Вот почему я бы предпочел использовать файл .

Поэтому я хотел бы создать экран, похожий на следующий...

      @Composable
fun MyScreen() {
    Scaffold(topBar = { T23TopAppBar() }) { paddingValues: PaddingValues ->
        Column(
            modifier = Modifier
                .padding(paddingValues)
                .fillMaxSize()
                //I want the full screen to be scrollable in case the content is too large
//                .verticalScroll(rememberScrollState()),
        ) {
            Text(
                text = "Lorem ipsum dolor sit amet",
                style = MaterialTheme.typography.h6,
                modifier = Modifier.padding(8.dp)
            )
            val showItems = remember { mutableStateOf(true) }
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.Center,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text("Show items: ")
                Switch(checked = showItems.value, onCheckedChange = { showItems.value = it })
            }
            Text(
                text = "GROUP 1",
                style = MaterialTheme.typography.overline,
                modifier = Modifier.padding(horizontal = 8.dp)
            )
            CardedLazyColumn(getItems(showItems.value))
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                text = "GROUP 2",
                style = MaterialTheme.typography.overline,
                modifier = Modifier.padding(horizontal = 8.dp)
            )
            CardedLazyColumn(persistentListOf("Lorem", "ipsum", "dolor", "sit", "amet"))
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                text = "GROUP 3",
                style = MaterialTheme.typography.overline,
                modifier = Modifier.padding(horizontal = 8.dp)
            )
            CardedLazyColumn(persistentListOf("Lorem", "ipsum", "dolor", "sit", "amet"))
        }
    }
}

Но поскольку элементов может быть больше, чем помещается на экране, я бы хотел, чтобы весь экран представлял собой прокручиваемый столбец для обработки, если элементов больше, чем помещается на экране. Но как только я добавлю.verticalScroll(rememberScrollState()), Compose выдает исключение ("IllegalStateException: вертикально прокручиваемый компонент был измерен с бесконечными ограничениями максимальной высоты, что запрещено...").

Я понимаю, что "вложенные компоненты, прокручиваемые в одном направлении" - это большое "нет-нет" . Но я даже не хочу, чтобы мои s можно было прокручивать. Я просто хочу иметь список переменной длины , который запекается в +animationвозможности, которых нет в обычном . И просто установив ' userScrollEnabledк falseне мешаетIllegalStateExceptionот броска.

Теперь мои вопросы:

  1. Есть ли какой-то обходной путь, чтобы заставить этот Carded работать внутри прокручиваемой колонки?
  2. Если нет, то есть ли реальный способ, по крайней мере, воспроизвести этот тип поведения? (Например, используя но с каким-то образом запеченной анимацией)
  3. Имеет ли смысл просто использовать обычный Carded и не включать анимацию?

Замена внешнего прокручиваемогоColumnс и каким-то образом сглаживая в каждой карте, чтобы бытьitemsпринадлежащийLazyColumnэто единственное, о чем я могу думать. Но это кажется слишком сложным. Например, первым элементом на карточке должна быть карточка со скругленными верхними углами, но обрезанная снизу. Для последнего элемента в карточке потребуется противоположное и т. д.

0 ответов

Другие вопросы по тегам