В нашем приложении нам нужно отображать постраничный список опций внутри раскрывающегося меню. Поскольку список данных является ленивым, его размер не является постоянным и, следовательно, может вызвать сбои, если вложенному составному элементу PaginatedLazyColumn() не присвоены значения постоянного размера. Очевидно, это выглядит плохо, поэтому мой вопрос: как мне к этому подойти?
Должен ли я каким-то образом вычислить ширину самой длинной строки данных (которая доступна на странице 0 полезных данных, поскольку, если появляется более длинная строка, ее можно обрезать) и установить ее как ширину раскрывающегося списка, сохраняя при этом высоту «комфортного» размера DP? Если да, то как я могу это сделать?
Я создал следующий составной объект, который представляет собой раскрывающийся список в нашем приложении:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LyraDropDown(
modifier: Modifier = Modifier,
data: List,
defaultSelectionIndex: Int = 0,
label: String,
onClick: (Int) -> Unit,
paginationCallback: () -> Unit = {},
itemContent: @Composable (String) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
var selectedIndex by remember { mutableIntStateOf(defaultSelectionIndex) }
val listWithDefaultOption = data.toMutableList()
listWithDefaultOption.add(0, "No selection")
ExposedDropdownMenuBox(
modifier = modifier.background(
colorResource(id = R.color.white),
shape = RoundedCornerShape(8.dp)
),
expanded = expanded, onExpandedChange = { expanded = !expanded }) {
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.menuAnchor()
.background(colorResource(id = R.color.white), shape = RoundedCornerShape(8.dp)),
readOnly = true,
label = {
Text(label, fontSize = 12.sp)
},
value = listWithDefaultOption[selectedIndex],
textStyle = TextStyle(fontSize = 12.sp),
onValueChange = { },
trailingIcon = {
Icon(
painter = painterResource(id = if (!expanded) R.drawable.ic_chev_down else R.drawable.ic_chev_up),
contentDescription = null,
modifier = Modifier
.size(24.dp)
.padding(4.dp),
tint = colorResource(id = R.color.gray_700)
)
},
shape = RoundedCornerShape(8.dp),
colors = ExposedDropdownMenuDefaults.outlinedTextFieldColors(
unfocusedContainerColor = colorResource(id = R.color.white),
focusedContainerColor = colorResource(id = R.color.white),
focusedBorderColor = colorResource(id = R.color.indigo_500),
unfocusedBorderColor = colorResource(id = R.color.gray_200),
focusedLabelColor = colorResource(id = R.color.blue_500),
unfocusedLabelColor = colorResource(id = R.color.black)
)
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
},
modifier = Modifier
.background(colorResource(id = R.color.white))
.width(200.dp)
.height(300.dp),
) {
PaginatedLazyColumn(
modifier = Modifier
.width(200.dp)
.height(300.dp),
items = listWithDefaultOption,
itemKey = { UUID.randomUUID() },
itemContentIndexed = { selectionOption, index ->
DropdownMenuItem(
onClick = {
selectedIndex = index
expanded = false
if (index != 0) onClick(index - 1) // account for hardcoded option
},
text = {
itemContent(selectionOption)
})
},
loadingItem = { LyraCircularProgressIndicator() },
contentWhenEmpty = { }) {
paginationCallback()
}
}
}
}
PaginatedLazyColumn определяется как:
@Composable
internal fun PaginatedLazyColumn(
modifier: Modifier = Modifier,
loading: Boolean = false,
listState: LazyListState = rememberLazyListState(),
items: List,
itemKey: (T) -> Any,
itemContentIndexed: @Composable (T, Int) -> Unit,
loadingItem: @Composable () -> Unit,
contentWhenEmpty: @Composable () -> Unit,
loadMore: () -> Unit
) {
val reachedBottom: Boolean by remember { derivedStateOf { listState.reachedBottom() } }
// load more if scrolled to bottom
LaunchedEffect(reachedBottom) {
if (reachedBottom && !loading) loadMore()
}
LazyColumn(modifier = modifier, state = listState) {
itemsIndexed(
items = items,
key = { _, item -> itemKey(item) }
) { index, item ->
itemContentIndexed(item, index)
}
if (items.isEmpty()) {
item {
contentWhenEmpty()
}
}
if (loading) {
item {
loadingItem()
}
}
}
}
private fun LazyListState.reachedBottom(buffer: Int = 1): Boolean {
val lastVisibleItem = this.layoutInfo.visibleItemsInfo.lastOrNull()
return lastVisibleItem?.index != 0 && lastVisibleItem?.index == this.layoutInfo.totalItemsCount - buffer
}
Подробнее здесь: https://stackoverflow.com/questions/781 ... eddropdown