0

我使用AnimatedVisibility动画从 a 中删除一个项目,LazyColumn以及MutableTransitionState捕捉动画的结尾以从LazyColumn的列表中删除该项目。

我为此编写了一个方便的扩展函数:

@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)
}

从某种意义上说,它返回正确的值(经过测试)是正确的,但currentState似乎false只是最初,所以我无法捕捉到我唯一感兴趣的事件 - 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的 aButton变为animationState.tagetValuefalse并且状态记录在卡内:

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?我做错了什么吗?

4

2 回答 2

1

每次更改状态时,都会触发相关视图重组。并且您animationState使用.true.apply { targetState = true }

很可能你想在一开始就显示它的动画,然后你需要使用LaunchedEffect: 当视图出现时它只会被调用一次。

val animationState = remember {
    MutableTransitionState(false)
}
LaunchedEffect(Unit) {
    animationState.targetState = true
}

在状态文档中阅读有关在 Compose 中思考和有关 Compose 中状态的更多信息。

于 2021-10-17T07:52:46.040 回答
0

经过一番测试...

我在一个单独的项目中测试了这种类型的动画,并发现AnimatedVisibility内容在animationState发出最终值之前就被释放了,所以你不可能从你正在制作动画的视图中捕捉到它。

遵循@Philip Dukhov 的建议,我LazyColumn的项目现在是这样的:

            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}")

这完美地捕获了发出的值。

但是,它存在严重的性能问题,logcat 显示:

I/Choreographer: Skipped 39 frames!  The application may be doing too much work on its main thread.
I/OpenGLRenderer: Davey! duration=992ms; Flags=0, IntendedVsync=189347804710717, Vsync=189348454710691, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=189348467819123, AnimationStart=189348467823342, PerformTraversalsStart=189348779946237, DrawStart=189348780275977, SyncQueued=189348792306499, SyncStart=189348792749051, IssueDrawCommandsStart=189348793026916, SwapBuffers=189348794352801, FrameCompleted=189348797854572, DequeueBufferDuration=181354, QueueBufferDuration=287916, GpuCompleted=188965731175579, 

而且我真的不知道如何避免它。

于 2021-10-17T10:22:09.713 回答