Android開源:GADownloading - 一個絢麗的下載動效分析與實現
閑逛之余,看到一個不錯的downloading動效,這個動效用CJJ的話說難度還好,但本人覺得還比較靈動、帶感、俏皮、有新意,好了話不多說,咱們先來擼一張高清無碼gif圖:
擼完,咱可以將整個動效簡單劃分為以下流程:
- BeforeProgress(顯示進度前);
- InProgress(顯示進度中);
3.Failed(失敗動畫);
4.Done(完成動畫);
下面咱們一起對以上流程進行分析與實現;
1. BeforeProgress(顯示進度前):
同樣,咱們一起擼一下第一部分高清無碼gif圖:
通過觀察,我們可以將以上動畫分割為以下幾個內容:
1.圓形背景和下載剪頭整體縮放;
2.圓形背景逐步鏤空(縮放到一定階段,內部鏤空圓不斷擴大);
3.圓形背景變為一條直線,并伴隨箭頭些許上移;
4.直線上下震蕩及下載箭頭(Arrow)變承載進度文字的線框形態;
1.1. 圓形背景和下載剪頭整體縮放:
這里面,圓形背景和整體的縮放好說,稍顯麻煩的是下載箭頭,由于后面箭頭還需要形變為承載進度文字的線框,所以丟掉你使用圖片的小想法,咱們一起用path勾一個活潑的小箭頭:
Paste_Image.png
箭頭OK了,圓形背景和整體的縮放就不再細說,只需要canvas.drawCircle()和使用ValueAnimator動態改變canvas縮放比例即可,so easy!
后面箭頭需要形變為承載進度文字的線框,通過觀察,可以看到線框的4個角是圓角。由于使用path勾勒,實現圓角線框大致有以下幾種方案:
1.使用path的quadTo()以二次貝塞爾曲線連接;
2.使用path的arcTo()以圓弧形式連接;
3.使用path中addArc()添加一段圓;
4.使用paint的setPathEffect設置PathEffect為ConnerPathEffect;
本人最終采用第四種方式進行實現;
1.2.圓形背景逐步鏤空(縮放到一定階段,內部鏤空圓不斷擴大):
擼完上圖,我們可看到,圓形背景由實心圓變換至一個圓環,最終消失,此處我們可以想到如下方案:
- 直接采用背景的顏色,在里面畫實心圓(需要提前知道背景顏色并且背景只能為純色);
- 外面深色的圓直接是圓環,然后通過調整圓的半徑及paint的strokeWidth實現;
3.直接采用混合模式(Xfermode),圓形背景中混合掉內圓部分;
第一種方案太挫,帥氣逼人的GAStudio哥肯定不會考慮,本文采用混合模式方案,關鍵代碼如下:
Paste_Image.png
1.3.圓形背景變為一條直線,并伴隨箭頭些許上移:
這個部分相比前面兩步稍顯復雜,需要將圓環如絲般順滑的變換成直線,并隨之上線震蕩,該過程拆解圖如下:
對于這個過程,GAStudio哥采用兩條三階貝塞爾曲線對初期的圓環、中間部分的曲線、最終的直線進行模擬;
為了便于理解,抽象出四個核心狀態,過程圖解如下:
1.完整圓形狀態:
2.延展開來狀態:
3.橫向鋪開狀態:
4.直線狀態:
更新path核心邏輯如下:
Paste_Image.png
Paste_Image.png
Paste_Image.png
整個過程路徑及控制點變化如下:
至此,箭頭上移的效果,只需根據繩子中心點的位置,平移下載箭頭位置即可;
1.4.直線上下震蕩及下載箭頭(Arrow)變承載進度文字的線框形態:
這個過程有以下三點需要考慮:
1.4.1.直線震蕩:
該效果僅需持續上下移動二階貝塞爾曲線的控制點即可,不再多言;
1.4.2.箭頭沿曲線移動:
移動的路線可以采用一個三階貝塞爾曲線進行模擬,再使用PathMeasure獲取過程中的實時位置(x、y),關鍵代碼如下:
Paste_Image.png
1.4.3.移動過程中的下載箭頭形態變換:
咱們用rectWidth、rectHeight分別指代下載箭頭底部的矩形部分的寬高,triWidth、triHeight分別指代Arrow頭部的三角形部分的寬高,angle指代下載箭頭的旋轉角度;
只需用ValueAnimator創建一個過程將以上數值進行如下變換:
rectWidth 到 2rectWidth;
rectHeight 到 1.4rectHeight 再到 rectHeight;
triWidth 到 0.65triWidth;
triHeight 到 0.65*triHeight;
angle 由 0 -> -30 -> 20 -> -10 -> 0度;
OK,到這里,第一部分就可以告一段落,咱們繼續看后面的部分;
2. InProgress(顯示進度中) :
GAStudio哥本次在實現過程中,沒有實現在移動的過程中的線框的搖擺,有興趣的同學可以自己修改實現,剩余部分主要講下拉繩的變動:
2.1. 拉繩的變動:
觀察上圖,可以將拉繩下拉的頂點移動的軌跡近似看成一條折線, 先計算出頂點的位置,再分別繪制左、右兩邊的直線,關鍵代碼如下:
Paste_Image.png
3. Failed(失敗動畫):
擼完以上gif,我們可以把這部分效果分為如下幾點:
1.線框內的文字變為Failed并且晃動;
2.繩子上下抖動;
3.繩子左側的白色部分爆炸消失;
4.線框回到最初位置,變且變為下載箭頭;
5.圓形背景逐漸放大出現;
6.圓形背景和下載箭頭整體縮放;
在這里,我們一起看下爆炸效果的實現,其他部分相對簡單,不再贅述;
關于爆炸效果,我們可以很逼真的模擬,繪制出各式各樣的圓點來模擬,但是由于點的個數多,大小不一,采用該方式費事費力,并且由于效果速度快,轉瞬即逝,我們可以采用一種簡單而效果看起來差不多的方式,就是只畫幾個形狀,然后平鋪到整個繩子;
該處主要使用paint的setPathEffect方法將PathEffect設置為PathDashPathEffect,關鍵代碼如下:
Paste_Image.png
4.Done(完成動畫):
擼完以上gif, 我們可以將該部分概括為以下部分:
-
線框繞Y軸旋轉,并由100%變換為done;
2.線框隨進度條收縮到最中心;
3.線框在中心點晃動;
4.線框變換為下載箭頭,圓形背景復出;
5.圓形背景和下載箭頭整體縮放,伴隨下載箭頭上下晃動;
該部分咱們一起看下第一條的實現,即Canvas里如何實現偽三維變換;
Canvas中只有rotate函數,也就是在二維平面內進行旋轉,不能實現如上的繞Y軸旋轉,類似效果需要借助Camera來實現,關鍵代碼如下:
Paste_Image.png
至此,該效果的核心邏輯咱們已經分析完畢,實現效果如下:
成功部分:
失敗部分:
你以為到這里就結束了嗎?No-No-No,作為一個負責任的開發者,最后咱們加上合理的自定義屬性,以方便使用者自行定義: