小弟才疏學淺,第一次寫簡書文章,內容難免有錯誤或者不妥,歡迎大家來指點江山。。。
先來看一下最終的效果:
特點:圓環是順時針旋轉,旋轉的過程中,始終保持圓環的開始端顏色最淺(白色),圓環的結尾是最深(0xEC1161).
在剛開始要做這個東西的時候,是因為想做一個下拉刷新的動畫,這個動畫要做到在下拉的過程中,有一個顏色漸變的圓環在變大,而且是要始終保濕圓環的開頭是白色,圓環的結尾是0xEC1161最深色。
想了幾個方法,都不太理想,其中包括在圓環的底部放置一個圓環圖片,下拉過程中,拖過CALayer的mask功能來把需要顯示的圓環給扣出來顯示,最終我采用了最簡單的方式,就是直接無限旋轉一個圓環圖片,醉了。。
這事完了之后,我不甘心,決定好好來實現以下這個動畫效果,就來了這個;下面簡要分析寫這個動畫的實現邏輯(可能對后續要實現一個進度條或者類似于360安全衛士清理時的進度條有一定的幫助)。
1. 這個圓環底部是一個UIView,在UIView上添加N(N>=2)個扇形的漸變CAGradientLayer,并讓這幾個扇形漸變的層正好布滿這個圓;
2. 這一系列扇形的CAGradientLayer的制作方法是:
a) 先畫一個UIView上半部分大小的CAGradientLayer;
b) 計算CAGradientLayer的startPoint和endPoint,這倆值的大小是根據1中的N決定的,N越大,endPoint.x-startPoint.x越小,而且endPoint.x和startPoint.x是以0.5為中心向兩邊偏移相等的距離,startPoint.x=0.5-sin(1.f/N*M_PI)/2.f,endPoint.x=0.5+sin(1.f/N*M_PI)/2.f,這里用到了簡單的直角三角形的sin函數計算;
c) 制作一個扇形的Layer,并把這個扇形Layer作為CAGradientLayer的mask,扇形Layer的UIBezierPath的繪制也是以中間為軸,向兩邊偏移,偏移的大小b中的計算是一樣的,startAngle=(-90.f/180.f*M_PI - 1.f/N*M_PI), endAngle=(-90.f/180.f*M_PI + 1.f/N*M_PI)
d) 最后,按照添加的次序,依次旋轉CAGradientLayer,使得N個Layer正好鋪成一個圓;
3. 然后在最上層添加一個CAShapeLayer,并且讓這個layer的frame的大小比最底層的UIView的frame稍微小一點(這個差值就是圓環的粗細),同時讓這個Layer的position等于UIView的center;
4. 稍微旋轉下最上層的CAShapeLayer,以做到等下針對該Layer的strokeStart做動畫時,能夠從中標的0點鐘位置開始,順時針方向做動畫;
5. 下面是動畫的部分,動畫分為兩個步驟,一個是針對oval.strokeStart的動畫,一個是針對N各扇形layer的locations的動畫
a) 針對oval.strokeStart的動畫簡單,執行N個單位時間,直接添加該動畫即可;
b) 針對N各扇形的動畫,是依次延遲 i (i從0開始)執行的,執行N-i個單位時間,并且每一個扇形的locations的開始值得第一個值是-i,第二個值是0,而且結束值得第一個值不變,第二個值是N-1,這是為什么呢?是因為要做到N個扇形的顏色能夠無縫銜接,具體原因上代碼(Talk is cheap, show me the code.),大家一看便明了(注:在初始化扇形Layer的時候,已經指定過了layer.locations=@[@(-i),@0.f]);
至此,大功告成,GradientLayerCount的值就是N,可以隨意修改配置,但是要保證大于等于2.
最后附上項目完整代碼鏈接(https://github.com/ShakeShakeMe/CircleProcessBar)。
修改:修改為可以手動執行動畫(也就是通過滑塊來執行動畫)。
(歡迎大家來踩)