iOS 自定義下拉線條動畫

本文摘錄自A GUIDE TO IOS ANIMATION,中文名:《Kitten 的 iOS 動畫學(xué)習(xí)手冊》。這是一本非常有趣地介紹 iOS 動畫的交互式電子書,提供生動的可交互式元素、視頻以及精心制作的配圖,讓你在前所未有的閱讀體驗中學(xué)到干貨。購買方式請看我的置頂微博。

這是本章的第二個 demo,下面這個案例中,我把線條動畫和數(shù)學(xué)知識結(jié)合在了一起。通過這個案例,可以很好地向你展示如何自己歸納出一個數(shù)學(xué)公式,并把它用到一個自定義動畫中。

首先,我們還是先看最終效果 :

OK,可以看到隨著手指在屏幕上滑動距離的改變,線條一開始逐漸靠攏,到達(dá)一定位置后開始彎曲,最終合并成了一個圓。順便一提,我已經(jīng)把這個動畫封裝到了一個上拉、下拉刷新的控件中,并且用在了大象公會這款獨(dú)立開發(fā)的 App 中。 你可以提前下載下來一睹實際效果。

下面講講我是怎么思考這個動畫的。首先,最終控制這個動畫進(jìn)度的是一個CALayer內(nèi)部的自定義的屬性:

@property(nonatomic,assign)CGFloatprogress;

無論你是通過手指滑動產(chǎn)生偏移量,還是滑動 UISlider 改變一個數(shù)值,最終都將轉(zhuǎn)化到這個屬性的改變。然后,在這個屬性的 setter 方法里,我們讓 layer 去實時地重繪,就像這樣:

-(void)setProgress:(CGFloat)progress{self.curveLayer.progress= progress;? ? [self.curveLayersetNeedsDisplay];}

至于重繪的算法,屬于細(xì)節(jié)上要考慮的事了。我們做一個動畫的步驟都是先考慮宏觀,再去考慮細(xì)節(jié)上的實現(xiàn)。就像開發(fā)一個 App 一樣,一開始肯定是先考慮架構(gòu),再去往這個框架里添磚加瓦,修修補(bǔ)補(bǔ)?,F(xiàn)在,我們對這個動畫的整體思路已經(jīng)清楚了,下面開始深入到細(xì)節(jié)去思考具體算法的實現(xiàn)。我把這個動畫分成了兩個階段:0~0.5 和 0.5~1.0。 這是什么意思?

做動畫還是那句話 ——「善于分解」。我們先看前半程,也就是 progress 從一開始的 0 運(yùn)動到中間狀態(tài) 0.5 的這一個階段。這一個階段兩條線段分別從上方和下方兩個方向向中間運(yùn)動,直到接觸到中線為止。這一階段的畫線算法非常簡單,只要能實時獲得 A,B 兩點的坐標(biāo),剩下用 UIBezierPath 的moveToPoint,addLineToPoint就完事了。所以,問題轉(zhuǎn)換成了求 A,B 兩點運(yùn)動的公式(其實只要求出一點,另一點無非就相差了一個線段長度 h)。請看演示動畫(注:在電子書中是有交互動畫的,但因為現(xiàn)在是以文章的形式呈現(xiàn),所以我只能通過圖片的方式向你展示)

其實你只要愿意動筆在紙上嘗試推演一番,并不難求得這兩個點的運(yùn)動公式:

yA = H/2 + h + (1-2*progress) * (H/2 - h)

yB = H/2 + (1-2*progress) * (H/2 - h)

接下來是動畫的第二階段 0.5~1.0。這個階段有些許復(fù)雜:「B 點保持不動,A 點繼續(xù)運(yùn)動到 B 的位置,同時,在頂部根據(jù)當(dāng)前的進(jìn)度再畫出圓弧」。視覺上給人的感覺就好像尾巴在逐漸縮短,頭部在慢慢彎曲。同樣的,我只能以圖片的形式向你展示。

在這個過程中,我們不難先求得 A 點的坐標(biāo)是:

yA = H/2 + h - h*(progress - 0.5) *2

比較麻煩的是這個圓弧該怎么畫?答案是可以用 UIBezierPath 中提供的- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise NS_AVAILABLE_IOS(4_0);這個方法繪制出圓弧。具體思路是:以CGPointMake(self.frame.size.width/2,self.frame.size.height/2)為圓心,10為半徑,按順時針方向,從M_PI(90°)的起始角度,畫到2*M_PI的結(jié)束角度。

關(guān)于- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;方法的解釋:如果設(shè)置開始角度均為 0 ,結(jié)束角度均為 π。那么設(shè)置 clockwise(順時針) 為 YES 時,畫出的是下半段圓弧;反之, 設(shè)置 clockwise(順時針) 為 NO 時,畫出的是上半段圓弧;

以上,我們只完成了一條線段的整個過程。同理,也能獲得另一條線段的繪制算法。最后,別忘了線段頂端還有個箭頭。繪制箭頭的算法 Gallery 4.1:我們以 B 點作為箭頭的起始起點,斜向左下方 30° 角延長 3 個單位。彎曲之后也同理,只需要額外加上線段轉(zhuǎn)過的角度即可。

相應(yīng)的代碼就是:

[arrowPath moveToPoint:pointB];[arrowPath addLineToPoint:CGPointMake(pointB.x-3*(cosf(Degree)), pointB.y+3*(sinf(Degree)))];[curvePath1 appendPath:arrowPath];

OK,這一個 demo 的分析到這里就結(jié)束了。完整代碼可以在本書對應(yīng)的Github Repo中下載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容