簡體   English   中英

如何在 Jetpack Compose 中為動態列表的元素設置動畫?

[英]How to animate elements of a dynamic list in Jetpack Compose?

如何使用動畫將列表的元素過渡到新列表(可能不同的大小)?

我有一個餅圖,當它的切片(分數)發生變化時,我想將以前的分數動畫化為新的分數。 問題是,每次切片的數量可能不同。

如果新切片的數量小於當前切片的數量,則當前額外的切片應該從它們的當前分數動畫到0
如果新切片的數量大於當前切片的數量,則新的額外切片應從0到它們的分數進行動畫處理。

@Composable fun PieChartCompose(slices: List<Float>) {
    val transitionData = updateTransitionData(slices)
    val fractions = transitionData.fractions
    // Draw the pie with Canvas using the fractions
}

我目前已經用一個恆定大小的列表(10,所以切片不能超過 10)來實現這個
(請注意,圖表外觀的初始動畫可能與后續動畫不同):

data class TransitionData(val slices: List<State<Float>>)

enum class ChartState { INITIALIZED, CHANGED }

@Composable fun updateTransitionData(
    targetFractions: List<Float>
): TransitionData {
    val mutableState = remember { MutableTransitionState(ChartState.INITIALIZED) }
    mutableState.targetState = ChartState.CHANGED
    val transition = updateTransition(mutableState, label = "main-animation")
    
    val fractions = listOf(
        transition.animateFloat(label = "fraction-0-animation") {
            if (it == ChartState.INITIALIZED) 0f
            else targetSlices.getOrNull(0)?.fraction ?: 0f
        },
        // ...
        transition.animateFloat(label = "fraction-10-animation") {
            if (it == ChartState.INITIALIZED) 0f
            else targetSlices.getOrNull(10)?.fraction ?: 0f
        }
    )
    return remember(transition) { TransitionData(fractions) }
}

下面是一個示例圖表,最初有兩個切片,然后動畫為一個切片
(第一個切片動畫為單個新分數,第二個切片動畫為0
由於插值和動畫規范,它們有點不一致):

示例所需的動畫

var slices by mutableStateOf(listOf(0.3f, 0.7f))
PieChartCompose(slices)
slices = listOf(1f)

您可以嘗試使用動態數量的animateFloat

由於我們想要為消失的分數制作動畫,我們需要知道舊的分數列表(以防它比新的大)。
這就是為什么我將轉換狀態更改為對分數列表進行操作的原因。 我們可以訪問“舊”狀態並找到“最大”大小(比較新舊分數列表大小)。
初始狀態是一個空列表,因此最初的第一個分數將從零開始動畫。

animateFloat我們嘗試從目標state獲取分數,如果該位置的分數不再存在 - 則將其設為零,這樣它就會消失。

我還添加了remember(values) { }周圍更新值animatedFractions它不需要工作,但它的存在而進行優化。 如果values的計數不會改變,那么所有現有對象都將被重用並且values列表應該相同——那么我們不需要用新的State對象更新animatedFractions

updateTransitionData返回一個穩定的對象,里面有穩定的列表。 我們只修改該列表內的對象。 因為它是一個SnapshotStateList ,它將負責刷新所有迭代它的Composables

@Composable
fun updateTransitionData(
    targetFractions: List<Float>
): TransitionData {
    val mutableState = remember { MutableTransitionState(emptyList<Float>()) }
    mutableState.targetState = targetFractions
    val transition = updateTransition(mutableState, label = "main-animation")

    val maxFractionsSize = max(transition.currentState.size, targetFractions.size)
    val values = (0 until maxFractionsSize).map { index ->
        transition.animateFloat(label = "fraction-$index-animation") { state ->
            state.getOrNull(index) ?: 0f
        }
    }

    val animatedFractions = remember(transition) { SnapshotStateList<State<Float>>() }
    remember(values) {
        animatedFractions.clear()
        animatedFractions.addAll(values)
    }
    return remember(transition) { TransitionData(animatedFractions) }
}

這是一個快速的“線性”演示,帶有減慢的動畫,通過 4 個不同的分數列表:
在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM