Как создать карту с ленивым вертикальным списком элементов, которые могут быть вложены в прокручиваемый столбец с помощью 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
от броска.
Теперь мои вопросы:
- Есть ли какой-то обходной путь, чтобы заставить этот Carded работать внутри прокручиваемой колонки?
- Если нет, то есть ли реальный способ, по крайней мере, воспроизвести этот тип поведения? (Например, используя но с каким-то образом запеченной анимацией)
- Имеет ли смысл просто использовать обычный Carded и не включать анимацию?
Замена внешнего прокручиваемогоColumn
с и каким-то образом сглаживая в каждой карте, чтобы бытьitems
принадлежащийLazyColumn
это единственное, о чем я могу думать. Но это кажется слишком сложным. Например, первым элементом на карточке должна быть карточка со скругленными верхними углами, но обрезанная снизу. Для последнего элемента в карточке потребуется противоположное и т. д.