欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中分析Jetpack?Compose動畫內(nèi)部的實現(xiàn)原理

 更新時間:2022年09月01日 08:48:09   作者:李小白lt???????  
這篇文章主要介紹了Android中分析Jetpack?Compose動畫內(nèi)部的實現(xiàn)原理,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下

前言

Compose的動畫Api用起來很簡單,效果看起來很神奇,那么它內(nèi)部到底是如何運轉(zhuǎn)的呢?

使用動畫的代碼示例:

var isOffset by remember { mutableStateOf(false) }
val offsetAnimation by animateDpAsState(targetValue = if (isOffset) 100.dp else 0.dp)
Button(
    onClick = { isOffset = !isOffset },
    modifier = Modifier.offset(0.dp, offsetAnimation)
) {
    Text(text = "點我進行位移")
}

看到有一個Boolean類型的isOffset狀態(tài),控制著offsetAnimation動畫,然后動畫又控制著Button的offset,最終實現(xiàn)了動畫效果

正文

我們主要就看一下animateDpAsState(animate*AsState)做了什么

跟一下animateDpAsState最后會走進animateValueAsState方法中:

方法內(nèi)部創(chuàng)建了一個Animatable動畫類

然后我們跟著上圖的箭頭看,在targetValue發(fā)生變化后,會通過channel來發(fā)送targetValue值的變化,然后launch啟動一個協(xié)程,并在其中調(diào)用了animatable的animateTo方法

接著我們就看看Animatable類是如何做動畫的:

主要就是內(nèi)部持有一個AnimationState類型(State)的internalState 變量,然后我們接著上面的代碼跟一下animateTo方法:

沒什么好說的,包了一下targetValue,接著就調(diào)用了runAnimation方法,接著往下跟(截不下分成兩張圖):

主要邏輯就是endState.animate()
endState就是copy的Animatable中的AnimationState對象internalState,也就是動畫的初始值

然后animation就是在animateTo方法中包裝了動畫目標值的對象

接著跟animate方法:

這個方法主要分為兩部分,第一部分就是構(gòu)建了一個AnimationScope,一個數(shù)據(jù)結(jié)構(gòu),用來存放動畫需要的一些信息

第二個部分就是真正動畫計算和生效的地方,doAnimationFrame

首先會在第一次創(chuàng)建AnimationScope的時候執(zhí)行一次(或再一下幀執(zhí)行一次,通過callWithFrameNanos方法)

然后會判斷如果動畫還未執(zhí)行完畢,就一直循環(huán)(while),一幀一幀執(zhí)行doAnimationFrame計算動畫的值

doAnimationFrame方法代碼:

其中通過時間等參數(shù)計算當前動畫應該設(shè)置的值,包括lastFrameTimeNanos和value等屬性,然后再最后調(diào)用updateState方法去將AnimationScope的值更新到AnimationState中

updatState方法代碼:

這個state對象其實也就是animateDpAsState中的Animatable動畫類中的AnimationState對象internalState

所以上面其實就是Compose中動畫的簡化流程

總結(jié)

由于AnimationState是一個State,在Compose中使用會自動監(jiān)聽其變化,只要其value變化了,就會導致相應位置重組,然后Composable就會使用新的值來展示不同的效果,

比如最開始的示例代碼:

var isOffset by remember { mutableStateOf(false) }
val offsetAnimation by animateDpAsState(targetValue = if (isOffset) 100.dp else 0.dp)
Button(
    onClick = { isOffset = !isOffset },
    modifier = Modifier.offset(0.dp, offsetAnimation)
) {
    Text(text = "點我進行位移")
}

在修改了isOffset后,animateDpAsState中的值就會因為動畫的計算和修改內(nèi)部state的value,導致Button的offset函數(shù)一直被重新調(diào)用,使Button不停的向下移動

其實Compose中的動畫如果不考慮那么多東西的話,可以簡化為如下代碼:

    /**
     * creator: lt
     * effect : 自定義的動畫播放器,邏輯更簡單
     * warning:
     * [initialValueWithState]動畫要改變的狀態(tài),起始動畫值為其value值
     * [targetValue]要通過動畫轉(zhuǎn)化到的目標值
     * [duration]動畫的持續(xù)時間
     */
    @OptIn(ExperimentalComposeApi::class)
    suspend fun animateWithFloat(
        initialValueWithState: MutableState<Float>,
        targetValue: Float,
        duration: Int = AnimationConstants.DefaultDurationMillis,
    ) {
        //動畫起始值,目標差值
        val startValue = initialValueWithState.value
        val valueToBeTransformed = targetValue - startValue
        //動畫起始時間,持續(xù)時間
        val startTime = System.nanoTime()
        val duration = duration * 1000000L
        //通過循環(huán)在下一幀計算動畫的值
        val frameClock = coroutineContext.monotonicFrameClock
        while (System.nanoTime() <= startTime + duration) {
            frameClock.withFrameNanos {
                //計算動畫的值,并設(shè)置值給狀態(tài)
                val progress = minOf(it - startTime, duration).toFloat() / duration
                val increase = progress * valueToBeTransformed
                initialValueWithState.value = startValue + increase
            }
        }
    }

使用方式如下,效果跟示例差不多:

ps:不建議線上項目用這個api,還是用系統(tǒng)的比較好,如果想使用也可以參考(歡迎star): ComposeViews/MAnimator.kt at main · ltttttttttttt/ComposeViews (github.com)

到此這篇關(guān)于Android中分析Jetpack Compose動畫內(nèi)部的實現(xiàn)原理的文章就介紹到這了,更多相關(guān)Android Jetpack Compose內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論