Jetpack Compose MutableTransitionState currentState содержит неправильное значение
я использую
AnimatedVisibility
для анимации удаления элемента из вместе с
MutableTransitionState
чтобы поймать конец анимации, чтобы удалить этот элемент из списка.
Для этого я составил удобную функцию расширения:
@ExperimentalTransitionApi
fun MutableTransitionState<Boolean>.transitionState(): TransitionState =
if (this.isIdle && this.currentState) TransitionState.Visible
else if (this.isIdle && !this.currentState) TransitionState.Invisible
else if (!this.isIdle && this.currentState) TransitionState.Disappearing
else TransitionState.Appearing
enum class TransitionState(private val whatever: Int) {
Visible(1),
Appearing(2),
Invisible(-1),
Disappearing(-2)
}
Это правильно в том смысле, что он возвращает правильные значения (проверено), но, похоже, только на начальном этапе, поэтому я не могу поймать единственное событие, которое меня интересует -
Invisible
.
Вот мой
LazyColumn
:
val items by viewModel.itemsFlow.collectAsState()
LazyColumn(
verticalArrangement = Arrangement.spacedBy(10.dp),
contentPadding = PaddingValues(horizontal = 15.dp, vertical = 15.dp)
) {
items(items) { item ->
val animationState = remember {
MutableTransitionState(false) // The only time currentState is false!
}.apply { targetState = true }
AnimatedVisibility(
visibleState = animationState,
enter = slideInVertically() + fadeIn(),
exit = slideOutHorizontally(
targetOffsetX = { it*2 },
animationSpec = tween(
durationMillis = 700
)
)
) {
ItemCard(
item = item,
viewModel = viewModel,
animationState = animationState
)
}
}
}
Мой
ItemCard
имеет
Button
это меняет
animationState.tagetValue
к, и состояние записывается внутри карты:
Card {
Log.v("ANIMATION", "View ${item.name} is now ${animationState.transitionState().name}")
Log.v("ANIMATION", "View ${item.name} has values: isIdle = ${animationState.isIdle}, currentState = ${animationState.currentState}")
/*...*/
Button(
/*...*/
onClick = {
animationState.targetState = false
}
) {/*...*/}
}
Мои журналы, к сожалению, такие:
V/ANIMATION: View name is now Appearing
V/ANIMATION: View name has values: isIdle = false, currentState = false
V/ANIMATION: View name is now Appearing
V/ANIMATION: View name has values: isIdle = false, currentState = false
V/ANIMATION: View name is now Visible
V/ANIMATION: View name has values: isIdle = true, currentState = true
V/ANIMATION: View name is now Visible
V/ANIMATION: View name has values: isIdle = true, currentState = true
// After I click the button:
V/ANIMATION: View name is now Disappearing
V/ANIMATION: View name has values: isIdle = false, currentState = true
V/ANIMATION: View name is now Disappearing
V/ANIMATION: View name has values: isIdle = false, currentState = true
V/ANIMATION: View name is now Disappearing
V/ANIMATION: View name has values: isIdle = false, currentState = true
Так где же невидимое состояние, т.е.
false
currentState
? Я сделал что-то не так?
2 ответа
После некоторого тестирования ...
Я тестировал этот тип анимации на отдельном проекте и выяснил, что
AnimatedVisibility
контент удаляется до
animationState
испускает свое окончательное значение, поэтому вы не сможете поймать его изнутри анимируемого вида.
Следуя совету @Philip Dukhov, мой
LazyColumn
s теперь выглядит так:
val animationState by remember {
mutableStateOf(MutableTransitionState(false))
}
LaunchedEffect(Unit) {
animationState.targetState = true
}
when(animationState.transitionState()) {
TransitionState.Invisible -> viewModel.deleteInvisibleItems()
else -> {}
}
Log.v("ANIMATION", "View ${item.name} is now ${animationState.transitionState().name}")
Это отлично улавливает испускаемые значения.
Каждый раз, когда вы меняете состояние, запускается перекомпоновка связанных представлений. И вы устанавливаете
animationState
к
true
на каждую перекомпоновку с
.apply { targetState = true }
.
Скорее всего, вы захотите показать его анимированным в начале, тогда вам нужно использовать LaunchedEffect
: он будет вызываться только один раз, когда появится представление.
val animationState = remember {
MutableTransitionState(false)
}
LaunchedEffect(Unit) {
animationState.targetState = true
}
Дополнительные сведения о перекомпоновках см. В разделе « Мышление в композиции» и о состоянии в разделе «Составление» в по документациисостояниям .