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, мой LazyColumns теперь выглядит так:

                  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
}

Дополнительные сведения о перекомпоновках см. В разделе « Мышление в композиции» и о состоянии в разделе «Составление» в по документациисостояниям .

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