Android動(dòng)效Compose貝塞爾曲線動(dòng)畫(huà)規(guī)格詳解
正文
寫(xiě)Compose動(dòng)畫(huà)的時(shí)候使用animateXAsState的時(shí)候會(huì)注意到一個(gè)參數(shù)——animationSpec,如下:
val borderRadius by animateIntAsState( targetValue = if (isRound) 100 else 0, animationSpec = tween( durationMillis = 3000, easing = LinearEasing ) )
此處就不深入探討不同的animationSpec類型有什么作用,主要看tween,它是幾乎最簡(jiǎn)單的一個(gè)類型,即使用緩動(dòng)曲線的起始點(diǎn)到終點(diǎn)的動(dòng)畫(huà)規(guī)格。
那么其中的easing參數(shù)就是該動(dòng)畫(huà)規(guī)格的緩動(dòng)曲線。什么是easing曲線,可以看下圖:
x軸可以理解為時(shí)間進(jìn)度,而y軸可以理解動(dòng)畫(huà)的進(jìn)度,可以看出該圖為線性曲線,即從頭到尾保持一樣的速度。關(guān)于各個(gè)不同的曲線產(chǎn)生不同的動(dòng)畫(huà)效果可以看下Android官網(wǎng)的Easing API,里面有比較多的動(dòng)圖來(lái)演示。
點(diǎn)進(jìn)tween源碼可以看到easing參數(shù)默認(rèn)使用FastOutSlowInEasing
曲線。
@Stable fun <T> tween( durationMillis: Int = DefaultDurationMillis, delayMillis: Int = 0, easing: Easing = FastOutSlowInEasing ): TweenSpec<T> = TweenSpec(durationMillis, delayMillis, easing)
根據(jù)名字可以看出FastOutSlowInEasing
為一開(kāi)始加速,收尾時(shí)減速的曲線。
點(diǎn)進(jìn)FastOutSlowInEasing
源碼可以看到官方內(nèi)置了多個(gè)曲線,其中有三個(gè)貝塞爾曲線,一個(gè)線性曲線。
val FastOutSlowInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f) val LinearOutSlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f) val FastOutLinearInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f) val LinearEasing: Easing = Easing { fraction -> fraction }
到這里就可以看到CubicBezierEasing
,即貝塞爾曲線。而這個(gè)就是本篇文章的主角。
貝塞爾曲線
貝塞爾曲線可以通過(guò)端點(diǎn)和把手精確地畫(huà)出想要的絲滑的曲線。
而上文中的三個(gè)內(nèi)置的貝塞爾曲線在制圖軟件中就如下(可能有些偏差):
但是曲線圖片和傳進(jìn)去的參數(shù)又有怎樣的映射關(guān)系呢?
還記得剛剛貝塞爾曲線的描述嗎?端點(diǎn)和把手來(lái)生成貝塞爾曲線。端點(diǎn)我們有了,即(0,0)和(1,1),那么我現(xiàn)在以FastOutSlowInEasing為例,把把手顯示出來(lái):
看到這里,其實(shí)答案很明確了!傳進(jìn)去的其實(shí)是把手的端點(diǎn)
- 第一個(gè)參數(shù)為起始點(diǎn)把手的x坐標(biāo)
- 第二個(gè)參數(shù)為起始點(diǎn)把手的y坐標(biāo)
- 第三個(gè)參數(shù)為終點(diǎn)把手的x坐標(biāo)
- 第四個(gè)參數(shù)為終點(diǎn)把手的y坐標(biāo)
CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)
知道這個(gè)原理之后就可以通過(guò)CubicBezierEasing
畫(huà)出各種想要的貝塞爾動(dòng)畫(huà)曲線了,而具體如何定義一根合理好看的動(dòng)畫(huà)的曲線就交給動(dòng)畫(huà)師吧!
解析動(dòng)畫(huà)曲線
我們打開(kāi)After Effects,畫(huà)一個(gè)小球,給小球的位置K兩個(gè)關(guān)鍵幀,并將兩個(gè)關(guān)鍵幀右鍵緩動(dòng)。如下:
點(diǎn)開(kāi)圖標(biāo)編輯器,之后就看到了兩根動(dòng)畫(huà)曲線
綠色那根是不是很熟悉!就是剛剛講的動(dòng)畫(huà)曲線(但是單位不一樣,之前的單位為百分比單位,0即未開(kāi)始,1為結(jié)束)從這里很清晰地看出x軸為時(shí)間,而Y軸則為動(dòng)畫(huà)的進(jìn)度,都是實(shí)際的值。這里就不多說(shuō)了,重點(diǎn)看白色那根動(dòng)畫(huà)曲線,可以猜猜是什么曲線。
恭喜你猜對(duì)了!是速度曲線。
在第一個(gè)格子的時(shí)候速度達(dá)到巔峰,因此可以看出綠色那根動(dòng)畫(huà)曲線在第一個(gè)格子的時(shí)候切線是最陡的,幾乎接近垂直,在開(kāi)始和結(jié)束的時(shí)候速度比較小,而此時(shí)的切線是平緩的。
將紅箭頭比作一個(gè)y = kx一元一次函數(shù)的話,而k的值就是白色曲線的y軸的值。
而該曲線則類似內(nèi)置的FastOutSlowInEasing
,先提高加速度,后減少加速度的曲線,導(dǎo)出動(dòng)畫(huà)效果如下。
曲線源碼分析
點(diǎn)進(jìn)Easing接口可以看到一個(gè)transform函數(shù),傳入一個(gè)Float類型的fraction
,返回一個(gè)Float類型的值。而這個(gè)其實(shí)就是x軸和y軸的值,即時(shí)間和進(jìn)度百分比,一般在0-1之間活動(dòng)。
@Stable fun interface Easing { fun transform(fraction: Float): Float }
而CubicBezierEasing
則繼承了Easing
,并實(shí)現(xiàn)了transform方法
@Immutable class CubicBezierEasing( private val a: Float, private val b: Float, private val c: Float, private val d: Float ) : Easing { ... private fun evaluateCubic(a: Float, b: Float, m: Float): Float { return 3 * a * (1 - m) * (1 - m) * m + 3 * b * (1 - m) * /* */ m * m + /* */ m * m * m } override fun transform(fraction: Float): Float { if (fraction > 0f && fraction < 1f) { var start = 0.0f var end = 1.0f while (true) { val midpoint = (start + end) / 2 val estimate = evaluateCubic(a, c, midpoint) if ((fraction - estimate).absoluteValue < CubicErrorBound) return evaluateCubic(b, d, midpoint) if (estimate < fraction) start = midpoint else end = midpoint } } else { return fraction } } ... }
但是公式我看不懂哈哈(= _=)。
進(jìn)階一點(diǎn)的話可以實(shí)現(xiàn)Easing來(lái)定義自己的曲線!
總結(jié)
其實(shí)我們很多APP對(duì)于動(dòng)畫(huà)的使用其實(shí)是非常局限的,包括曲線!我們大多數(shù)動(dòng)畫(huà)都在使用生硬的線性動(dòng)畫(huà),其中一個(gè)原因就是程序員和設(shè)計(jì)師的交流隔了一個(gè)專業(yè),實(shí)際溝通比較困難。
以上就是Android動(dòng)效Compose貝塞爾曲線動(dòng)畫(huà)規(guī)格詳解的詳細(xì)內(nèi)容,更多關(guān)于Android Compose貝塞爾曲線的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android Dialog 對(duì)話框詳解及示例代碼
本文主要介紹Android Dialog,這里詳細(xì)介紹Android Dialog的基本使用方法,并提供了示例代碼和實(shí)現(xiàn)效果圖,有需要的小伙伴可以參考下2016-08-08Android?自定義view中根據(jù)狀態(tài)修改drawable圖片
這篇文章主要介紹了Android?自定義view中根據(jù)狀態(tài)修改drawable圖片的相關(guān)資料,需要的朋友可以參考下2023-07-07Android實(shí)現(xiàn)返回拍攝的圖片功能實(shí)例
這篇文章主要介紹了Android實(shí)現(xiàn)返回拍攝的圖片功能,以實(shí)例形式較為詳細(xì)的分析了Android返回拍攝圖片功能的具體步驟與實(shí)現(xiàn)方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07Android使用SwipeListView實(shí)現(xiàn)類似QQ的滑動(dòng)刪除效果
這篇文章主要介紹了Android使用SwipeListView實(shí)現(xiàn)類似QQ的滑動(dòng)刪除效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08在android開(kāi)發(fā)中進(jìn)行數(shù)據(jù)存儲(chǔ)與訪問(wèn)的多種方式介紹
很多時(shí)候我們的軟件需要對(duì)處理后的數(shù)據(jù)進(jìn)行存儲(chǔ)或再次訪問(wèn),Android為數(shù)據(jù)存儲(chǔ)提供了多種方式,首先給大家介紹使用文件如何對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ),感興趣的朋友可以了解下哈2013-06-06Android編程開(kāi)發(fā)之TextView單擊鏈接彈出Activity的方法
這篇文章主要介紹了Android編程開(kāi)發(fā)之TextView單擊鏈接彈出Activity的方法,涉及Android中TextView控件的相關(guān)操作技巧,需要的朋友可以參考下2016-01-01Android JSON數(shù)據(jù)與實(shí)體類之間的相互轉(zhuǎn)化(GSON的用法)
這篇文章主要介紹了Android JSON數(shù)據(jù)與實(shí)體類之間的相互轉(zhuǎn)化(GSON的用法),非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-01-01Android自定義View仿IOS圓盤(pán)時(shí)間選擇器
這篇文章主要介紹了Android自定義View仿IOS圓盤(pán)時(shí)間選擇器,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03