Compose?動(dòng)畫(huà)藝術(shù)探索之可見(jiàn)性動(dòng)畫(huà)示例詳解
正文
本篇文章是此專欄的第二篇文章,上一篇文章簡(jiǎn)單寫了下 Compose
的動(dòng)畫(huà),讓大家先看了下 Compose
開(kāi)箱即用的動(dòng)畫(huà)效果,效果還是挺好的,感興趣的可以去看下:Compose 動(dòng)畫(huà)藝術(shù)探索之瞅下 Compose 的動(dòng)畫(huà)
從可見(jiàn)性動(dòng)畫(huà)看起
可見(jiàn)性動(dòng)畫(huà)在上一篇文章中介紹過(guò),不過(guò)只是簡(jiǎn)單使用,沒(méi)看過(guò)上一篇文章的也不用擔(dān)心,給大家看下可見(jiàn)性動(dòng)畫(huà)的實(shí)際效果。
實(shí)現(xiàn)代碼也很簡(jiǎn)單,來(lái)回顧下:
val visible = remember { mutableStateOf(true) } AnimatedVisibility(visible = visible.value,) { Text(text = "天青色等煙雨,而我在等你,炊煙裊裊升起,隔江千萬(wàn)里") }
上一篇文章主要介紹了 Compose
動(dòng)畫(huà)的便攜之處,例如上面代碼,確實(shí)非常簡(jiǎn)單就能實(shí)現(xiàn)之前原生安卓中比較難實(shí)現(xiàn)的動(dòng)畫(huà)效果,今天咱們就來(lái)稍微深入一點(diǎn)看看,從小節(jié)標(biāo)題也能知道,就從可見(jiàn)性動(dòng)畫(huà)來(lái)看!
怎么看呢?直接點(diǎn)進(jìn)去源碼來(lái)看!先來(lái)看看 AnimatedVisibility
的函數(shù)定義吧!
@Composable fun AnimatedVisibility( visible: Boolean, modifier: Modifier = Modifier, enter: EnterTransition = fadeIn() + expandIn(), exit: ExitTransition = shrinkOut() + fadeOut(), label: String = "AnimatedVisibility", content: @Composable() AnimatedVisibilityScope.() -> Unit ) { val transition = updateTransition(visible, label) AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content) }
其實(shí)可組合項(xiàng) AnimatedVisibility
不是只有這一個(gè),目前 Compose 1.3.0-beta02
版本中有六個(gè),這個(gè)咱們待會(huì)再說(shuō),先看這一個(gè),也是第一個(gè),可以看到函數(shù)中一共可以接收六個(gè)參數(shù),下面先來(lái)看看這六個(gè)參數(shù)分別有什么作用吧:
- visible:定義內(nèi)容是否應(yīng)該可見(jiàn),true 為可見(jiàn),false 為不可見(jiàn)
- modifier:修飾符,這個(gè)就不多說(shuō)了,在
Compose
中Modifier
簡(jiǎn)直隨處可見(jiàn) - enter:內(nèi)容出現(xiàn)時(shí)的動(dòng)畫(huà),可以看到這個(gè)參數(shù)有默認(rèn)值,默認(rèn)值為
fadeIn() + expandIn()
,大致意思為淡入并擴(kuò)展開(kāi) - exit:內(nèi)容由可見(jiàn)變?yōu)椴豢梢?jiàn)時(shí)的動(dòng)畫(huà),同樣的,這個(gè)參數(shù)也有默認(rèn)值,默認(rèn)值為
shrinkOut() + fadeOut()
,大致意思為縮小并淡出消失 - label:字面意思理解為標(biāo)簽,默認(rèn)值為
AnimatedVisibility
,可以自定義做標(biāo)記,用于區(qū)分不同動(dòng)畫(huà) - content:需要添加可見(jiàn)性動(dòng)畫(huà)的可組合項(xiàng)。
上面這些參數(shù)除了 enter
和 exit
外都比較好理解,這里就不做過(guò)多解釋,重點(diǎn)來(lái)看下 enter
和 exit
,可以看到 enter
的類型為 EnterTransition
,exit
的類型為 ExitTransition
,那么接下來(lái)咱們來(lái)分別看看 EnterTransition
和 ExitTransition
吧!
這里其實(shí)有一個(gè)小問(wèn)題,可以看到上面 Gif 圖中并不是淡入并擴(kuò)展和縮小并消失,這是為什么呢?繼續(xù)往下看就能找到答案!
進(jìn)入過(guò)渡——EnterTransition
顧名思義,這個(gè)類主要是為了做進(jìn)入過(guò)渡的,來(lái)簡(jiǎn)單看下它的源碼吧:
@Immutable sealed class EnterTransition { internal abstract val data: TransitionData // 組合不同的進(jìn)入轉(zhuǎn)換。組合的順序并不重要,因?yàn)檫@些將同時(shí)啟動(dòng) @Stable operator fun plus(enter: EnterTransition): EnterTransition { return EnterTransitionImpl( TransitionData( fade = data.fade ?: enter.data.fade, slide = data.slide ?: enter.data.slide, changeSize = data.changeSize ?: enter.data.changeSize, scale = data.scale ?: enter.data.scale ) ) } companion object { // 當(dāng)不需要輸入轉(zhuǎn)換時(shí),可以使用此函數(shù)。 val None: EnterTransition = EnterTransitionImpl(TransitionData()) } }
可以看到 EnterTransition
是一個(gè)密封類, 類中有一個(gè)抽象的不可變值 data
,類型為 TransitionData
,這個(gè)放到下面來(lái)說(shuō);類中還有一個(gè)函數(shù),而且該函數(shù)有 operator
前綴, 這表示運(yùn)算符重載,重載了“+”號(hào),所以就可以使用“+”來(lái)組合不同的輸入動(dòng)畫(huà)了,函數(shù)接收的參數(shù)也是 EnterTransition
,然后直接返回 EnterTransitionImpl
,又沒(méi)見(jiàn)過(guò),怎么辦?繼續(xù)看看 EnterTransitionImpl
是個(gè)啥!
@Immutable private class EnterTransitionImpl(override val data: TransitionData) : EnterTransition()
可以看到 EnterTransitionImpl
類很簡(jiǎn)單,是一個(gè)私有類,繼承自 EnterTransition
,注意類上有 Immutable
注解, Immutable
注解可用于將類標(biāo)記為生成不可變實(shí)例,但類的不變性沒(méi)有得到驗(yàn)證,它是類型的一種承諾,即在構(gòu)造實(shí)例之后,所有公開(kāi)可訪問(wèn)的屬性和字段都不會(huì)更改。 EnterTransitionImpl
還需要實(shí)現(xiàn)父類的抽象值,所有有 TransitionData
類型的參數(shù) data
,上面咱們簡(jiǎn)單提到了 TransitionData
,這里來(lái)看下吧!
@Immutable internal data class TransitionData( val fade: Fade? = null, val slide: Slide? = null, val changeSize: ChangeSize? = null, val scale: Scale? = null )
可以看到 TransitionData
類也有 Immutable
注解,這里就不做過(guò)多介紹,這是一個(gè)包內(nèi)可見(jiàn)的數(shù)據(jù)類,里面有四個(gè)不可變值,分別是 Fade
、Slide
、ChangeSize
、Scale
,其實(shí)從名稱就能看出這幾個(gè)參數(shù)分別代表的意思,不過(guò)還是來(lái)看下它們的源碼吧!
@Immutable internal data class Fade(val alpha: Float, val animationSpec: FiniteAnimationSpec<Float>) @Immutable internal data class Slide( val slideOffset: (fullSize: IntSize) -> IntOffset, val animationSpec: FiniteAnimationSpec<IntOffset> ) @Immutable internal data class ChangeSize( val alignment: Alignment, val size: (fullSize: IntSize) -> IntSize = { IntSize(0, 0) }, val animationSpec: FiniteAnimationSpec<IntSize>, val clip: Boolean = true ) @Immutable internal data class Scale( val scale: Float, val transformOrigin: TransformOrigin, val animationSpec: FiniteAnimationSpec<Float> )
可以看到這四個(gè)類都是不可變的數(shù)據(jù)類,分別表示顏色轉(zhuǎn)變、滑動(dòng)、大小變化及縮放。這幾個(gè)類有一個(gè)共同點(diǎn),都有一個(gè)共同的參數(shù) animationSpec
,參數(shù)類型為 FiniteAnimationSpec
,來(lái)看看 FiniteAnimationSpec
是個(gè)啥?
interface FiniteAnimationSpec<T> : AnimationSpec<T> { override fun <V : AnimationVector> vectorize( converter: TwoWayConverter<T, V> ): VectorizedFiniteAnimationSpec<V> }
可以看到 FiniteAnimationSpec
是一個(gè)接口,繼承自 AnimationSpec
,簡(jiǎn)單理解就是有限動(dòng)畫(huà)規(guī)格,定義了動(dòng)畫(huà)的時(shí)長(zhǎng)及動(dòng)畫(huà)效果等,類似于原生安卓中的什么呢?嗯。。。差值器吧!FiniteAnimationSpec
是所有非無(wú)限動(dòng)畫(huà)實(shí)現(xiàn)的接口,包括: TweenSpec
, SpringSpec
, KeyframesSpec
, RepeatableSpec
, SnapSpec
等等,上一篇文章中說(shuō)到的無(wú)限循環(huán)動(dòng)畫(huà) InfiniteRepeatableSpec
沒(méi)有繼承這個(gè)接口,其實(shí)從名字看就知道了,InfiniteRepeatableSpec
也繼承自 AnimationSpec
。。。。
不行不行,扯太遠(yuǎn)了,其實(shí)看源碼就是這樣,看著看著一直往下看就會(huì)迷失了最初的目標(biāo),越看越多,越看越多,這里就先不接著往下看了,再看就沒(méi)完沒(méi)了了,這里咱們知道這四個(gè)類大概存儲(chǔ)了什么數(shù)據(jù)就行了。動(dòng)畫(huà)規(guī)格咱們放到之后的文章中慢慢看,今天主要來(lái)過(guò)一遍可見(jiàn)性動(dòng)畫(huà)!
簡(jiǎn)單總結(jié)下, EnterTransition
類中有一個(gè)函數(shù),進(jìn)行了運(yùn)算符重載,可以有多個(gè)動(dòng)畫(huà)同時(shí)進(jìn)行。
關(guān)閉過(guò)渡——ExitTransition
其實(shí)看完剛才的 EnterTransition
類再來(lái)看 ExitTransition
就會(huì)覺(jué)得很簡(jiǎn)單了,不信的話咱們來(lái)看下 ExitTransition
的源碼:
@Immutable sealed class ExitTransition { internal abstract val data: TransitionData // 結(jié)合不同的退出轉(zhuǎn)換,組合順序并不重要 @Stable operator fun plus(exit: ExitTransition): ExitTransition { return ExitTransitionImpl( TransitionData( fade = data.fade ?: exit.data.fade, slide = data.slide ?: exit.data.slide, changeSize = data.changeSize ?: exit.data.changeSize, scale = data.scale ?: exit.data.scale ) ) } companion object { // 當(dāng)不需要內(nèi)置動(dòng)畫(huà)時(shí)使用 val None: ExitTransition = ExitTransitionImpl(TransitionData()) } }
是不是基本一致,連抽象不可變值都一摸一樣,甚至值的名稱都沒(méi)變!唯一不同的是 EnterTransition
的實(shí)現(xiàn)類為 EnterTransitionImpl
,而 ExitTransition
的子類為 ExitTransitionImpl
,那就再看看 ExitTransitionImpl
!
@Immutable private class ExitTransitionImpl(override val data: TransitionData) : ExitTransition()
和 EnterTransitionImpl
不能說(shuō)相似,只能說(shuō)一摸一樣。。。所以就不做過(guò)多介紹。。。
過(guò)渡——Transition
文章開(kāi)頭的時(shí)候看 AnimatedVisibility
函數(shù)中只有下面的兩行代碼,
val transition = updateTransition(visible, label) AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
這一小節(jié)咱們先來(lái)看第一行,可以看到調(diào)用了 updateTransition
函數(shù), 傳入了當(dāng)前顯示狀態(tài)和標(biāo)簽,來(lái)具體看下這個(gè)函數(shù)吧!
@Composable fun <T> updateTransition( targetState: T, label: String? = null ): Transition<T> { val transition = remember { Transition(targetState, label = label) } transition.animateTo(targetState) DisposableEffect(transition) { onDispose { // 出去的時(shí)候清理干凈,確保觀察者不會(huì)被困在中間狀態(tài) transition.onTransitionEnd() } } return transition }
可以看到這個(gè)函數(shù)也是一個(gè)可組合項(xiàng),返回值為 Transition
,函數(shù)中先記住并構(gòu)建了一個(gè) Transition
,然后調(diào)用了 Transition
的 animateTo
函數(shù)來(lái)執(zhí)行過(guò)渡動(dòng)畫(huà),然后調(diào)用了需要清理的效應(yīng) DisposableEffect
,之后在 onDispose
中調(diào)用了 onTransitionEnd
函數(shù),以防卡在這里,最后返回剛才構(gòu)建的 Transition
。
函數(shù)中的內(nèi)容不難理解,現(xiàn)在唯一困惑的是 Transition
是個(gè)什么東西!那就來(lái)看看!
@Stable class Transition<S> @PublishedApi internal constructor( private val transitionState: MutableTransitionState<S>, val label: String? = null )
這就是 Transition
的類聲明,Transition
在狀態(tài)級(jí)別上管理所有子動(dòng)畫(huà)。子動(dòng)畫(huà)可以使用Transition
以聲明的方式創(chuàng)建。animateFloat
、animateValue
、animateColor
animateColor
等。當(dāng) targetState
改變時(shí),Transition
將自動(dòng)啟動(dòng)或調(diào)整其所有子動(dòng)畫(huà)的路線,使其動(dòng)畫(huà)到為每個(gè)動(dòng)畫(huà)定義的新目標(biāo)值。
可以看到 Transition
構(gòu)造函數(shù)中接收一個(gè) MutableTransitionState
類型的參數(shù)和一個(gè) lable
,但咱們看到上面?zhèn)魅氲牟⒉皇?MutableTransitionState
類型的參數(shù),肯定還有別的構(gòu)造函數(shù)!
internal constructor( initialState: S, label: String? ) : this(MutableTransitionState(initialState), label)
沒(méi)錯(cuò),確實(shí)還有一個(gè)構(gòu)造函數(shù),接下來(lái)看下 MutableTransitionState
吧!
class MutableTransitionState<S>(initialState: S) { // 當(dāng)前的狀態(tài) var currentState: S by mutableStateOf(initialState) internal set // 過(guò)渡的目標(biāo)狀態(tài) var targetState: S by mutableStateOf(initialState) // 是否空閑 val isIdle: Boolean get() = (currentState == targetState) && !isRunning // 是否運(yùn)行 internal var isRunning: Boolean by mutableStateOf(false) }
可以看到 MutableTransitionState
中構(gòu)建了幾個(gè)需要的狀態(tài),具體表示什么在上面代碼中添加了注釋。
過(guò)渡動(dòng)畫(huà)實(shí)現(xiàn)——AnimatedEnterExitImpl
剛才看了 AnimatedVisibility
函數(shù)中的第一行代碼,下面咱們來(lái)看下第二行代碼:
AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
這塊調(diào)用了一個(gè)實(shí)現(xiàn)函數(shù),將剛構(gòu)建好的 Transition
和之前的 EnterTransition
、ExitTransition
統(tǒng)統(tǒng)傳了進(jìn)去,下面就來(lái)看下 AnimatedEnterExitImpl
!
@Composable private fun <T> AnimatedEnterExitImpl( transition: Transition<T>,visible: (T) -> Boolean, modifier: Modifier,enter: EnterTransition, exit: ExitTransition,content: @Composable() AnimatedVisibilityScope.() -> Unit ) { val isAnimationVisible = remember(transition) { mutableStateOf(visible(transition.currentState)) } if (visible(transition.targetState) || isAnimationVisible.value || transition.isSeeking) { val childTransition = transition.createChildTransition(label = "EnterExitTransition") { transition.targetEnterExit(visible, it) } LaunchedEffect(childTransition) { snapshotFlow { childTransition.currentState == EnterExitState.Visible || childTransition.targetState == EnterExitState.Visible }.collect { isAnimationVisible.value = it } } AnimatedEnterExitImpl(childTransition,modifier, enter = enter,exit = exit,content = content ) } }
這塊代碼有點(diǎn)多啊,但不要害怕,可以看到基本上這里使用到的類在剛才咱們都看過(guò)了,接下來(lái)需要的就是一行一行往下看,看看哪個(gè)沒(méi)見(jiàn)過(guò)咱們?cè)倏矗?/p>
函數(shù)中先記錄了當(dāng)前的狀態(tài),然后判斷當(dāng)前的狀態(tài)值是否為 true,如果為 true 的話則創(chuàng)建子過(guò)渡,老規(guī)矩,來(lái)看看 createChildTransition
!
@Composable inline fun <S, T> Transition<S>.createChildTransition( label: String = "ChildTransition", transformToChildState: @Composable (parentState: S) -> T, ): Transition<T> { val initialParentState = remember(this) { this.currentState } val initialState = transformToChildState(if (isSeeking) currentState else initialParentState) val targetState = transformToChildState(this.targetState) return createChildTransitionInternal(initialState, targetState, label) }
可以看到 createChildTransition
是 Transition
的一個(gè)擴(kuò)展函數(shù),還是一個(gè)高階函數(shù),函數(shù)內(nèi)獲取了高階函數(shù)中的返回值,然后直接返回調(diào)用了 createChildTransitionInternal
,并傳入獲取的值,這個(gè)值目前還不知道是什么,只知道是 targetEnterExit
返回的數(shù)據(jù),這個(gè)一會(huì)再看,先接著看 createChildTransitionInternal
函數(shù):
@Composable internal fun <S, T> Transition<S>.createChildTransitionInternal( initialState: T, targetState: T, childLabel: String, ): Transition<T> { val transition = remember(this) { Transition(MutableTransitionState(initialState), "${this.label} > $childLabel") } DisposableEffect(transition) { addTransition(transition) onDispose { removeTransition(transition) } } if (isSeeking) { transition.setPlaytimeAfterInitialAndTargetStateEstablished( initialState, targetState, this.lastSeekedTimeNanos ) } else { transition.updateTarget(targetState) transition.isSeeking = false } return transition }
可以看到 createChildTransitionInternal
也是 Transition
的一個(gè)擴(kuò)展函數(shù),然后函數(shù)中也使用了需要清理的效應(yīng),之后判斷 isSeeking
的值是,isSeeking
的值在 setPlaytimeAfterInitialAndTargetStateEstablished
函數(shù)中會(huì)被置為 true,如果 isSeeking
值為 true 則調(diào)用 setPlaytimeAfterInitialAndTargetStateEstablished
函數(shù),用來(lái)設(shè)置初始狀態(tài)和目標(biāo)狀態(tài)建立后的時(shí)間,如果為 false,則更新?tīng)顟B(tài)值。
到這里 createChildTransition
函數(shù)咱們大概看了下,但剛才還有一個(gè)扣,剛才說(shuō)了不知道目標(biāo)值是什么,因?yàn)槟鞘?targetEnterExit
的返回值,現(xiàn)在咱們來(lái)看看!
@Composable private fun <T> Transition<T>.targetEnterExit( visible: (T) -> Boolean, targetState: T ): EnterExitState = key(this) { if (this.isSeeking) { if (visible(targetState)) { Visible } else { if (visible(this.currentState)) { PostExit } else { PreEnter } } } else { val hasBeenVisible = remember { mutableStateOf(false) } if (visible(currentState)) { hasBeenVisible.value = true } if (visible(targetState)) { EnterExitState.Visible } else { // If never been visible, visible = false means PreEnter, otherwise PostExit if (hasBeenVisible.value) { EnterExitState.PostExit } else { EnterExitState.PreEnter } } } }
同樣的,targetEnterExit
也是一個(gè)擴(kuò)展函數(shù),返回值為 EnterExitState
。這里也使用了 isSeeking
來(lái)進(jìn)行判斷,然后根據(jù)當(dāng)前的值來(lái)設(shè)置不同的 EnterExitState
。EnterExitState
又是個(gè)啥呢???接著來(lái)看!
enum class EnterExitState { // 自定義進(jìn)入動(dòng)畫(huà)的初始狀態(tài)。 PreEnter, // 自定義進(jìn)入動(dòng)畫(huà)的目標(biāo)狀態(tài),也是動(dòng)畫(huà)過(guò)程中自定義退出動(dòng)畫(huà)的初始狀態(tài)。 Visible, // 自定義退出動(dòng)畫(huà)的目標(biāo)狀態(tài)。 PostExit }
奧,EnterExitState
只是一個(gè)枚舉類,定義了三種狀態(tài):初始狀態(tài)、進(jìn)入動(dòng)畫(huà)的狀態(tài)和退出動(dòng)畫(huà)的狀態(tài)。
下面接著來(lái)看 AnimatedEnterExitImpl
:
LaunchedEffect(childTransition) { snapshotFlow { childTransition.currentState == EnterExitState.Visible || childTransition.targetState == EnterExitState.Visible }.collect { isAnimationVisible.value = it } } AnimatedEnterExitImpl(childTransition,modifier, enter = enter,exit = exit,content = content )
這里使用了 LaunchedEffect
效應(yīng),并使用 snapshotFlow
將 State
轉(zhuǎn)為了 Flow
,然后將值設(shè)置到 isAnimationVisible
。
后面又調(diào)用了相同名字的一個(gè)函數(shù) AnimatedEnterExitImpl
:
@Composable private inline fun AnimatedEnterExitImpl( transition: Transition<EnterExitState>, modifier: Modifier, enter: EnterTransition, exit: ExitTransition, content: @Composable AnimatedVisibilityScope.() -> Unit ) { if (transition.currentState == EnterExitState.Visible || transition.targetState == EnterExitState.Visible ) { val scope = remember(transition) { AnimatedVisibilityScopeImpl(transition) } Layout( content = { scope.content() }, modifier = modifier.then(transition.createModifier(enter, exit, "Built-in")), measurePolicy = remember { AnimatedEnterExitMeasurePolicy(scope) } ) } }
函數(shù)名字一樣,但參數(shù)不同,這里將剛才構(gòu)建好的 Transition<EnterExitState>
傳了進(jìn)來(lái),然后函數(shù)內(nèi)先對(duì)狀態(tài)進(jìn)行了過(guò)濾,然后構(gòu)建了 Layout
。
Layout
中設(shè)置了 modifier
,modifier
調(diào)用了 then
函數(shù),then
函數(shù)用于將此修飾符與另一個(gè)修飾符連接,然后連接了 transition.createModifier(enter, exit, "Built-in")
,大家發(fā)現(xiàn)點(diǎn)什么沒(méi)有,這里使用到了上面咱們構(gòu)建好了所有東西。。。那么。。。。哈哈哈哈!
柳暗花明
下面咱們就來(lái)看看 transition.createModifier
這個(gè)函數(shù),先來(lái)看下函數(shù)體:
@Composable internal fun Transition<EnterExitState>.createModifier( enter: EnterTransition, exit: ExitTransition, label: String ): Modifier
嗯,沒(méi)錯(cuò),是 Transition<EnterExitState>
的一個(gè)擴(kuò)展函數(shù),也是一個(gè)可組合項(xiàng)!接著往下看幾行代碼:
var modifier: Modifier = Modifier modifier = modifier.slideInOut( this, rememberUpdatedState(enter.data.slide), rememberUpdatedState(exit.data.slide), label ).shrinkExpand( this, rememberUpdatedState(enter.data.changeSize), rememberUpdatedState(exit.data.changeSize), label )
構(gòu)建了一個(gè) Modifier
,然后調(diào)用了 slideInOut
和 shrinkExpand
,沒(méi)錯(cuò),這是滑動(dòng)和縮小放大!接著來(lái)!
var shouldAnimateAlpha by remember(this) { mutableStateOf(false) } var shouldAnimateScale by remember(this) { mutableStateOf(false) } if (currentState == targetState && !isSeeking) { shouldAnimateAlpha = false shouldAnimateScale = false } else { if (enter.data.fade != null || exit.data.fade != null) { shouldAnimateAlpha = true } if (enter.data.scale != null || exit.data.scale != null) { shouldAnimateScale = true } }
創(chuàng)建兩個(gè)值來(lái)記錄是否需要透明度的轉(zhuǎn)換和縮放!下面來(lái)看下執(zhí)行的代碼:
if (shouldAnimateScale) { ...... modifier = modifier.graphicsLayer { this.alpha = alpha this.scaleX = scale this.scaleY = scale this.transformOrigin = transformOrigin } } else if (shouldAnimateAlpha) { modifier = modifier.graphicsLayer { this.alpha = alpha } }
嗯呢,是不是豁然開(kāi)朗!但是 slideInOut
和 shrinkExpand
函數(shù)也是可見(jiàn)性動(dòng)畫(huà)這里定義的 Modifier
的擴(kuò)展函數(shù),里面還有一些自定義的東西,但這不是本文的重點(diǎn)了。
別的可見(jiàn)性動(dòng)畫(huà)
文章開(kāi)頭說(shuō)了,可見(jiàn)性動(dòng)畫(huà)目前一共有六個(gè),聽(tīng)著很嚇人,其實(shí)大同小異,來(lái)簡(jiǎn)單看下不同吧!
@Composable fun RowScope.AnimatedVisibility( visible: Boolean, modifier: Modifier = Modifier, enter: EnterTransition = fadeIn() + expandHorizontally(), exit: ExitTransition = fadeOut() + shrinkHorizontally(), label: String = "AnimatedVisibility", content: @Composable() AnimatedVisibilityScope.() -> Unit ) { val transition = updateTransition(visible, label) AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content) } @Composable fun ColumnScope.AnimatedVisibility( visible: Boolean, modifier: Modifier = Modifier, enter: EnterTransition = fadeIn() + expandVertically(), exit: ExitTransition = fadeOut() + shrinkVertically(), label: String = "AnimatedVisibility", content: @Composable AnimatedVisibilityScope.() -> Unit ) { val transition = updateTransition(visible, label) AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content) }
上面這兩個(gè)和咱們上面說(shuō)的基本一樣,只不過(guò)一個(gè)是 RowScope
的擴(kuò)展函數(shù),另一個(gè)是 ColumnScope
的擴(kuò)展函數(shù),并且在默認(rèn)動(dòng)畫(huà)上還有些區(qū)別,RowScope
默認(rèn)是橫向的擴(kuò)展和收縮,ColumnScope
是縱向的擴(kuò)展和收縮,更加方便咱們?nèi)粘U{(diào)用!這也就解釋了文章開(kāi)頭提出的小問(wèn)題!
接著再來(lái)看別的!
@Composable fun AnimatedVisibility( visibleState: MutableTransitionState<Boolean>, modifier: Modifier = Modifier, enter: EnterTransition = fadeIn() + expandIn(), exit: ExitTransition = fadeOut() + shrinkOut(), label: String = "AnimatedVisibility", content: @Composable() AnimatedVisibilityScope.() -> Unit ) { val transition = updateTransition(visibleState, label) AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content) }
這個(gè)和之前的就有點(diǎn)區(qū)別了,第一個(gè)參數(shù)就不同了,參數(shù)類型為 MutableTransitionState
,其實(shí)是一樣的,咱們上面也都說(shuō)到了,MutableTransitionState
的使用方法在上一篇文章中也介紹過(guò),感興趣的可以去看一下。
剩下的兩個(gè)還是 RowScope
和 ColumnScope
的擴(kuò)展函數(shù),也是參數(shù)類型改為了 MutableTransitionState
,這里也就不做過(guò)多介紹。
結(jié)尾
本篇文章帶大家看了可見(jiàn)性動(dòng)畫(huà)的一些源碼,很多其實(shí)都是點(diǎn)到為止,并沒(méi)有一致不斷深入,一直深入就會(huì)陷入其中,忘了看源碼的本意,本文所有源碼基于 Compose 1.3.0-beta02
。
本文至此結(jié)束,有用的地方大家可以參考,當(dāng)然如果能幫助到大家,更多關(guān)于Compose 可見(jiàn)性動(dòng)畫(huà)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Compose開(kāi)發(fā)之動(dòng)畫(huà)藝術(shù)探索及實(shí)現(xiàn)示例
- 使用Compose制作抖音快手視頻進(jìn)度條Loading動(dòng)畫(huà)效果
- Jetpack Compose實(shí)現(xiàn)列表和動(dòng)畫(huà)效果詳解
- Jetpack Compose實(shí)現(xiàn)動(dòng)畫(huà)效果的方法詳解
- 通過(guò)Jetpack Compose實(shí)現(xiàn)雙擊點(diǎn)贊動(dòng)畫(huà)效果
- 利用Jetpack Compose繪制可愛(ài)的天氣動(dòng)畫(huà)
相關(guān)文章
Android游戲開(kāi)發(fā):實(shí)現(xiàn)手勢(shì)操作切換圖片的實(shí)例
本文主要介紹 Android游戲開(kāi)發(fā)實(shí)現(xiàn)手勢(shì)操作切換圖片的實(shí)例,這里整理了詳細(xì)的資料和示例代碼,有開(kāi)發(fā)Android游戲應(yīng)用的小伙伴可以參考下2016-08-08Android 實(shí)現(xiàn)把bitmap圖片的某一部分的顏色改成其他顏色
這篇文章主要介紹了Android 實(shí)現(xiàn)把bitmap圖片的某一部分的顏色改成其他顏色,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04android基礎(chǔ)總結(jié)篇之八:創(chuàng)建及調(diào)用自己的ContentProvider
這篇文章主要介紹了android基礎(chǔ)總結(jié)篇之八:創(chuàng)建及調(diào)用自己的ContentProvider,有興趣的可以了解一下。2016-11-11發(fā)布?Android?library?到?Maven?解析
這篇文章主要介紹了發(fā)布?Android?library到Maven解析,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09Android實(shí)現(xiàn)APP自動(dòng)更新功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)APP自動(dòng)更新功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Android自定義驗(yàn)證碼輸入框的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Android自定義驗(yàn)證碼輸入框的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02Android實(shí)現(xiàn)ListView的A-Z字母排序和過(guò)濾搜索功能 實(shí)現(xiàn)漢字轉(zhuǎn)成拼音
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)ListView的A-Z字母排序和過(guò)濾搜索功能,實(shí)現(xiàn)漢字轉(zhuǎn)成拼音功能2017-06-06