Этот код не работает должным образом. Я хочу, чтобы ленивый столбец автоматически прокручивался вверх, чтобы отображать всю высоту карты при расширении.
val listState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
LazyColumn(
state = listState
) {
itemsIndexed(items) { index, item ->
ExpandableCard(
item = item,
isExpanded = expandedCardsStates[item.id] ?: false,
onCardClicked = {
viewModel.expandedState(item.id)
coroutineScope.launch {
listState.animateScrollToItem(index = index)
}
}
)
}
}
Вот как это выглядит с этим кодом, когда я раскрываю последнюю карточку:
Вот ожидаемое поведение:
Использование animateScrollToItem
не даст вам удовлетворительных результатов. Он попытается прокрутить LazyColumn так, чтобы заданный item
оказался вверху LazyColumn. Если item
будет последним на экране, анимация будет заикаться. Другая проблема заключается в том, что прокрутка может уже выполняться во время анимации, в результате чего элемент будет виден не полностью.
Вероятно, вам нужно прокручивать LazyColumn только в том случае, если развернутый элемент не полностью виден на экране. Чтобы обнаружить такие случаи, добавьте модификатор onGoballyPositioned
к AnimatedVisibility
:
@Composable
fun ExpandableCard(/** ... **/ ) {
var isFullyVisible by remember {
mutableStateOf(true) // stores whether the expanded content is fully visible on screen
}
var contentHeightPx by remember {
mutableStateOf(0f) // stores the height of the expanded content
}
Card(
//...
) {
Column(
modifier = Modifier.padding(16.dp)
) {
// ...
AnimatedVisibility(
modifier = Modifier.onGloballyPositioned { coordinates ->
val (width, height) = coordinates.size
val (x1, y1) = coordinates.positionInRoot()
val x2 = x1 + width
val y2 = y1 + height
val screenWidth: Float = configuration.screenWidthDp.toPx
val screenHeight: Float = configuration.screenHeightDp.toPx
isFullyVisible = (x1 >= 0 && y1 >= 0) && (x2 <= screenWidth && y2 <= screenHeight)
contentHeightPx = coordinates.size.height.toFloat()
},
visible = isExpanded,
enter = expandVertically() + fadeIn(),
exit = shrinkVertically() + fadeOut()
) {
//...
}
}
}
}
Вам необходимо добавить следующую функцию расширения:
val Number.toPx
get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
Resources.getSystem().displayMetrics
)
Далее нам нужно убедиться, что прокрутка выполняется только после завершения анимации AnimatedVisibility. Нам нужно добавить отдельную функцию обратного вызова в ExpandableCard
Composable. Кроме того, мы меняем тип возвращаемого значения функции onCardClicked
с Job на Unit
:
@Composable
fun ExpandableCard(/** ... **/ onCardClicked: () -> Unit, onCardExpanded: (Float) -> Job) {
//...
}
Затем мы вызываем onCardExpanded
после завершения анимации расширения:
AnimatedVisibility(
//...
) {
val animatedVisibilityScope = this
LaunchedEffect(animatedVisibilityScope.transition.isRunning) {
if (!animatedVisibilityScope.transition.isRunning &&
animatedVisibilityScope.transition.currentState == EnterExitState.Visible
) {
if (!isFullyVisible) {
// If the content is not fully visible, scroll LazyColumn
onCardExpanded(contentHeightPx)
}
}
}
// expanded content
}
Наконец, примените прокрутку в LazyColumn:
LazyColumn(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp, end = 20.dp, top = 20.dp),
state = listState
) {
itemsIndexed(items) { index, item ->
ExpandableCard(
engagementPointItem = item,
isExpanded = expandedCardsStates[item.id] ?: false,
onCardClicked = {
viewModel.toggleExpandedState(item.id)
},
onCardExpanded = { scrollAmount ->
coroutineScope.launch {
listState.animateScrollBy(scrollAmount + 50)
}
}
)
}
}
Выход:
Что вы подразумеваете под «картой над экраном»? Можете ли вы поделиться видео проблемы? Кроме того, длина содержимого карты не должна иметь значения, поскольку требуемая высота рассчитывается динамически. Он будет прокручиваться настолько, насколько высока высота содержимого.
в отправленном вами видео при открытии первой отображенной карты (например, карты номер 31) она открывается вверх, а не вниз. в некоторых случаях, подобных этому, это делается неправильно
Можете ли вы поделиться своим кодом на GitHub, пожалуйста?
Я только что увидел, что в моем ответе отсутствует одна функция расширения, я отредактировал свое сообщение. Также вот ссылка на фрагмент: gitlab.com/-/snippets/3721931 Для простоты я использовал Column
вместо LazyColumn
. Таким образом, мне не нужно использовать ViewModel для хранения развернутого/свернутого состояния.
это работает! большое спасибо
спасибо, но карточки над экраном при открытии раскрываются неправильно. Обратите внимание, что содержимое карточки длинное (приблизительно 10 строк)