最近在學(xué)習(xí)CALayer相關(guān)動(dòng)畫,然后某一天突然發(fā)現(xiàn)蘋果安裝app這動(dòng)畫就很不錯(cuò)啊,所以就想自己實(shí)現(xiàn)下。
具體效果如圖:
還是不試不知道一試嚇一跳啊,這看上去簡(jiǎn)單的動(dòng)畫沒我想象的那么簡(jiǎn)單。
首先這個(gè)動(dòng)畫分兩步:
一是中間的圓像時(shí)鐘一樣走一圈;
二是外面的大圓變大到包括整個(gè)圖片的大小;
首先是第一步:
這時(shí)候大圓外部跟小圓內(nèi)部都是半透明的,小圓走過(guò)的部分會(huì)變成透明。
一開始我一直想用mask的方式來(lái)實(shí)現(xiàn),結(jié)果試了老好久還是不行,就扔那兒了。
過(guò)了兩天再看它,發(fā)現(xiàn)其實(shí)自己想復(fù)雜了,從表面看的話,
第一部分的動(dòng)畫是畫一個(gè)圓,然后用一個(gè)顏色填充它,中間就是畫圓的一部分然后填充,問(wèn)題是這樣一點(diǎn)點(diǎn)走的動(dòng)畫好難實(shí)現(xiàn);
所以我就想如果是自己用筆畫的話要怎么辦?
然后發(fā)現(xiàn)用筆畫的話,只要用跟半徑一樣寬的線來(lái)畫就很easy了,畫多少就是多少,想停哪兒就停哪兒!
然后跟代碼一對(duì)照才恍然大悟,CAShapeLayer就有l(wèi)ineWidth這個(gè)屬性啊,也這么畫就很簡(jiǎn)單了!
(這里需要注意CAShapeLayer計(jì)算fillColor的范圍時(shí),是按照線的中心計(jì)算的,所以實(shí)際在代碼中線寬是半徑2倍)
透明的問(wèn)題也是一樣,根本不用什么mask,畫的時(shí)候是覆蓋上去,那畫反過(guò)來(lái)不就是一點(diǎn)點(diǎn)露出來(lái)了嘛!!!
放到代碼里的話,讓strokeEnd從1變到0就ok了。 (這里需要注意方向的問(wèn)題,貝塞爾曲線有取反方向的方法,設(shè)置path的時(shí)候注意)
那剩下的問(wèn)題是:怎么畫一個(gè)中間圓透明,圓與邊框之間半透明的圖形出來(lái)?
我首先想到的是。。。。做個(gè)圖片。。。然后試了試,果然可以!不過(guò)第二步的動(dòng)畫沒法做了。。。
所以還是得用CAShapeLayer自己畫。。。
這里經(jīng)春哥指點(diǎn)才解決了這個(gè)問(wèn)題,用到了一個(gè)比較高端的參數(shù),就是CAShapeLayer的fillRule參數(shù)。
有兩個(gè)可選值kCAFillRuleEvenOdd 和 kCAFillRuleNonZero
大致是:
nonzero字面意思是“非零”。按該規(guī)則,要判斷一個(gè)點(diǎn)是否在圖形內(nèi),從該點(diǎn)作任意方向的一條射線,然后檢測(cè)射線與圖形路徑的交點(diǎn)情況。從0開始計(jì)數(shù),路徑從左向右穿過(guò)射線則計(jì)數(shù)加1,從右向左穿過(guò)射線則計(jì)數(shù)減1。得出計(jì)數(shù)結(jié)果后,如果結(jié)果是0,則認(rèn)為點(diǎn)在圖形外部,否則認(rèn)為在內(nèi)部。下圖演示了nonzero規(guī)則:

evenodd字面意思是“奇偶”。按該規(guī)則,要判斷一個(gè)點(diǎn)是否在圖形內(nèi),從該點(diǎn)作任意方向的一條射線,然后檢測(cè)射線與圖形路徑的交點(diǎn)的數(shù)量。如果結(jié)果是奇數(shù)則認(rèn)為點(diǎn)在內(nèi)部,是偶數(shù)則認(rèn)為點(diǎn)在外部。下圖演示了evenodd 規(guī)則:
具體就是先畫一個(gè)矩形,然后再用 appendPath方法添加一個(gè)圓進(jìn)去作為整個(gè)CAShapeLayer的path;(也可以用 moveToPoint方法);
利用fillRule讓它圓內(nèi)部透明,外部半透明。
然后把這個(gè)layer add 上去就可以了。
剩下的就是一個(gè)stokeEnd的動(dòng)畫,就簡(jiǎn)單了。
第二步:讓大圓的半徑變大
這個(gè)只是個(gè)path動(dòng)畫,這里的大圓是上面第一步中最后那個(gè)方法畫出來(lái)的,只需要設(shè)置path為最終的大小就可以了,也比較簡(jiǎn)單
還有一些細(xì)節(jié)見代碼注釋;