亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Android如何實現(xiàn)自定義的動畫曲線

 更新時間:2022年04月11日 08:41:45   作者:島上碼農(nóng)  
最近在寫動畫相關(guān)的篇章,經(jīng)常會用到 Curve 這個動畫曲線類,那這個類到底怎么實現(xiàn)的?如果想自己來一個自定義的動畫曲線該怎么弄?本文將為大家詳細(xì)解答

前言

最近在寫動畫相關(guān)的篇章,經(jīng)常會用到 Curve 這個動畫曲線類,那這個類到底怎么實現(xiàn)的?如果想自己來一個自定義的動畫曲線該怎么弄?本篇我們就來一探究竟。

曲線

Curve 類定義

查看源碼, Curve 類定義如下:

abstract?class?Curve?extends?ParametricCurve<double>?{
??const?Curve();

??@override
??double?transform(double?t)?{
????if?(t?==?0.0?||?t?==?1.0)?{
??????return?t;
????}
????return?super.transform(t);
??}
??
??Curve?get?flipped?=>?FlippedCurve(this);
}

看上去好像沒定義什么, 實際這里只是做了兩個處理,一個是明確的數(shù)據(jù)類型為 double,另一個是對 transform 做了重載,也只是對參數(shù) t 做了特殊處理,保證參數(shù) t 的范圍在0-1之間,且起點值0.0和終點值1.0不被轉(zhuǎn)換函數(shù)轉(zhuǎn)換。主要定義在上一層的ParametricCurve。文檔是建議子類重載transformInternal方法,那我們就繼續(xù)往上看ParametricCurve這個類的實現(xiàn),代碼如下:

abstract?class?ParametricCurve<T>?{
??const?ParametricCurve();

??T?transform(double?t)?{
????assert(t?!=?null);
????assert(t?>=?0.0?&&?t?<=?1.0,?'parametric?value?$t?is?outside?of?[0,?1]?range.');
????return?transformInternal(t);
??}

??@protected
??T?transformInternal(double?t)?{
????throw?UnimplementedError();
??}

??@override
??String?toString()?=>?objectRuntimeType(this,?'ParametricCurve');
}

可以看到,實際上 transform 方法除了做參數(shù)合法性驗證以外,其實就是調(diào)用了transformInternal方法,因此子類必須要實現(xiàn)該方法,否則會拋出UnimplementedError異常。

實例解析

上面的源碼可以看到,關(guān)鍵在于參數(shù) t。這個參數(shù) t 代表什么呢?注釋里說的是:

Returns the value of the curve at point t. — 返回 t 點的曲線對應(yīng)的值。

因此 t 可以認(rèn)為是曲線的橫坐標(biāo),而為了保證曲線的一致性,做了歸一化處理,也就是t的取值都是在0-1之間。這么說可能有點抽象,我們來看2個例子來對比就明白了,先看最簡單 Curves.linear 的實現(xiàn)。

class?_Linear?extends?Curve?{
??const?_Linear._();

??@override
??double?transformInternal(double?t)?=>?t;
}

超級簡單吧,直接返回 t,其實對應(yīng)我們的數(shù)學(xué)的函數(shù)就是:

y?=?f(t)?=?t

對應(yīng)的曲線就是一條斜線。也就是說在設(shè)定的動畫時間內(nèi),會完成從0-1的線性轉(zhuǎn)變,也就是變化是均勻的。線性這個很好理解,我們再來看一個減速曲線decelerate的實現(xiàn)。

class?_DecelerateCurve?extends?Curve?{
??const?_DecelerateCurve._();

??@override
??double?transformInternal(double?t)?{
????t?=?1.0?-?t;
????return?1.0?-?t?*?t;
??}
}

我們先看一下_DecelerateCurve 的計算表達(dá)式是什么。

回憶一下我們高中物理學(xué)的勻減速運動,加速度為負(fù)(即減速)的距離計算公式:

上面的減速曲線其實就可以看做是初始速度是2,加速度也是2的減速運動。為什么要是2這個值呢,這是因為 t 的取值范圍是0-1,這樣計算完的結(jié)果的取值范圍還是0-1。你肯定會問,為什么要保證曲線的計算結(jié)果要是0-1?我們來假設(shè)計算結(jié)果不為0-1會發(fā)生什么情況,比如我們要在屏幕上移動一個組件為60像素。假設(shè)動畫曲線初始值不為0。那就意味著一開始的移動距離是跳變的。同樣的,如果結(jié)束值不為1.0,意味著在最后一個點的距離值不是60.0,那么就意味著結(jié)束時需要從最后一個點跳到最終的60像素的位置(動畫需要保證最終的移動距離是60像素)這樣意味著動畫會出現(xiàn)跳變的效果,繪制曲線的話會是下面的樣子(綠色是正常的,紅線是異常的)。這樣的動畫體驗是很糟糕的!因此,這是一個關(guān)鍵點,如果你的自定義曲線的 transformInternal 方法的返回值范圍不是0-1,就意味著動畫會出現(xiàn)跳變,導(dǎo)致動畫缺幀的感覺。

image.png

有了這個基礎(chǔ),我們就可以解釋動畫曲線的基本機制了,實際上就是在給定的動畫時間(Duration)范圍內(nèi),完成組件的初始狀態(tài)到結(jié)束狀態(tài)的轉(zhuǎn)變,這個轉(zhuǎn)變是沿著設(shè)定的 Curve 類完成的,而其橫坐標(biāo)是0-1.0,曲線的初始值和結(jié)束值分別是0和1.0,而至于中間值是可以低于0或超過1的。我們可以想像是我們沿著設(shè)定的曲線運動,最終無論如何都會達(dá)到設(shè)定的目的地,而至于怎么走,拐多少道彎,速度怎么變化都是曲線控制的。但是,如果你的曲線初始值不為0或結(jié)束值不為1,就像是跳懸崖的那種感覺!

正弦動畫曲線

我們來一個正弦曲線的動畫驗證一下上面的說法。

class?SineCurve?extends?Curve?{
??final?int?count;
??const?SineCurve({this.count?=?1})?:?assert(count?>?0);

??@override
??double?transformInternal(double?t)?{
????return?sin(2?*?count*?pi?*?t);
??}
}

count 參數(shù)用于控制周期,即達(dá)到目的地之前可以多來幾個來回。這里我們發(fā)現(xiàn),初始值是0,但是一個周期(2π)結(jié)束值也是0,這樣在動畫結(jié)束前會出現(xiàn)跳變的結(jié)果。來看一下示例代碼,這個示例是讓圓形向下移動60像素。

AnimatedContainer(
??decoration:?BoxDecoration(
????color:?Colors.blue,
????borderRadius:?BorderRadius.circular(30.0),
??),
??transform:?Matrix4.identity()..translate(0.0,?up???60.0?:?0.0,?0.0),
??duration:?Duration(milliseconds:?3000),
??curve:?SineCurve(count:?1),
??child:?ClipOval(
????child:?Container(
??????width:?60.0,
??????height:?60.0,
??????color:?Colors.blue,
????),
??),
)

運行效果如下,注意看最后一幀從0的位置直接跳到了60的位置。

跳動動畫

這個怎么調(diào)呢,我們來看一下正弦曲線的樣子。

正弦曲線

如果我們要滿足0-1范圍的要求,那么要往后再移動90度才能夠達(dá)到。但是,這樣還有個問題,這樣破壞了周期性,比如設(shè)置 count=2的時候結(jié)果又不對了。我們來看一下規(guī)律,實際上只有第一個周期需要多移動90度(圖中箭頭指向的點),后面的都是按360度(即2π)為周期了。也就是角度其實是按2.5π,4.5π,6.5π……規(guī)律來的,對應(yīng)的角度公式其實就是:

所以調(diào)整后的正弦曲線代碼為:

class?SineCurve?extends?Curve?{
??final?int?count;
??const?SineCurve({this.count?=?1})?:?assert(count?>?0);

??@override
??double?transformInternal(double?t)?{
????//?需要補償pi/2個角度,使得起始值是0.終止值是1,避免出現(xiàn)最后突然回到0
????return?sin(2?*?(count?+?0.25)?*?pi?*?t);
??}
}

再看調(diào)整后的效果,是不是絲滑般地過渡了?

總結(jié)

本篇介紹了 Flutter 動畫曲線類的原理和控制動畫的機制,實際上 Curve 類就是在指定的時間內(nèi),沿曲線完成從起點到終點的過渡。但是為了保證動畫平滑過渡,應(yīng)該保證自定義曲線的transformInternal方法返回值的起始值和結(jié)束值分別是0和1。

到此這篇關(guān)于詳解Android如何實現(xiàn)自定義的動畫曲線的文章就介紹到這了,更多相關(guān)Android動畫曲線內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論