撰写自定义布局中的 animateFloatAsState 未对所有可组合项进行动画处理

animateFloatAsState in compose custom layout not animating all composables

我有一个自定义布局,它是一个类似日历的屏幕,用户可以将其作为一个整体拖动。在屏幕上可见的时间范围内对用户可见的事件使用 placeables/measurable.

绘制

我有一个功能,当用户将事件部分拖出屏幕时,内容中的标题会粘在事件的顶部,直到它被完全拖出屏幕。

发生这种情况时,我会在顶部添加一个小图像以指示事件在其上方继续进行

例如

"Event Name"

变成

^
"Event Name"

我想为“事件名称”文本设置动画,使其随着 ^ 出现或消失而向下移动,而不是当我 insert/remove 重新组合 ^ 时它简单地向下跳。

看起来这就是我需要的正确动画文本

@Composable
fun TestItem(event: Event) {
    val offset: Float by animateFloatAsState(if (event.isPartiallyOffScreen)) 100f else 0f)

    Box(Modifier.background(color=event.color)) {
        Text(
            text = event.name,
            modifier = Modifier.graphicsLayer(
                translationY = offset
            )
         )
    }
} 

当内容在 on/off 屏幕之间切换时,这确实使文本平滑地向下和向上动画,但问题是,我在屏幕上有几十个这样的东西,它只适用于第一个项目在一列中,直到出现间隙。

事件 811 将在文本离开屏幕时将其动画化,当事件 195 开始离开屏幕时,它会在它发生的那一刻从 0 跳到 100,然后事件 757 将工作并正确地为文本设置动画,尽管在之后做个动图,757也有点卡顿了。

这几乎就像是因为事件 811 可组合项在完全离开屏幕后就不再存在,它认为事件 195 是事件 811,因为它占据了可放置顺序中的那个位置,现在它开始离开屏幕并重复使用之前的事件价值观?当它达到 757 时,它已经消失了很多次,它有点像预期的那样工作?

更新:我已经确认,如果我停止从列表中删除项目(如果它们不在屏幕上),它将按预期在所有项目上工作,但性能下降和卡顿是相当大的,因为有超过 80-正在绘制 100 个项目,大部分都在屏幕外,所以这不是一个真正的选择。

我也尝试过使用 LaunchedEffects 以及来自事件的唯一键,但它也不起作用?

这是可组合项中唯一有状态的东西,其他一切都只是从构造函数内容中设置的值

我对如何解决这个问题感到困惑。

在确认如果我不移除屏幕外可组合项我的屏幕将正常工作后,它证实了我的怀疑,即由于所有项目都相同,重新组合变得混乱。

我以为在动画上使用键可以解决问题,但事实并非如此。我需要的是这个答案中描述的可组合项的键

所以对我来说,我需要将自定义布局中的每个事件包装在 key 可组合项

 Layout(
    modifier = modifier.fillMaxHeight()
    content = {
        eventList.forEach { event ->
           key(event) {
               TestItem(displayPerformance, adjustedStart)
           }
        }
    },
) { measureables, constraints ->