老司機(jī)帶你走進(jìn)Core Animation 之幾種動(dòng)畫(huà)的簡(jiǎn)單應(yīng)用

老司機(jī)帶你走進(jìn)Core Animation 之幾種動(dòng)畫(huà)的簡(jiǎn)單應(yīng)用

系列文章:


之所以要寫(xiě)這幾種簡(jiǎn)單應(yīng)用呢,是為了幫大家擴(kuò)展一下思維,基于CAAnimationCADisplayLink其實(shí)我們可以做到很多事情,不過(guò)我們都還是需要一個(gè)思路。有的時(shí)候可能,拿到一個(gè)效果,我們一眼就可以看出來(lái),哦,使用核心動(dòng)畫(huà)就可以搞定,然而真正上手的時(shí)候就會(huì)發(fā)現(xiàn),哦,沒(méi)有想象的那么簡(jiǎn)單,為什么我達(dá)到的效果不對(duì)呢?一般情況下有兩種可能,要么是思路不完整,要么是思路根本就不對(duì)。CAAnimation固然靈活,但要是使用方法不當(dāng)?shù)脑?,也?huì)事倍功半。所以呢,今天老司機(jī)就針對(duì)以下幾種情況來(lái)介紹截個(gè)動(dòng)畫(huà)的實(shí)現(xiàn)方式。(說(shuō)這么多其實(shí)就是因?yàn)檫@段時(shí)間一直研究這個(gè),的確也沒(méi)研究別的,哈哈哈)

在這篇文章中你會(huì)看到以下一些內(nèi)容:

  • iOS中GIF動(dòng)圖的播放的實(shí)現(xiàn)方式

  • iOS系統(tǒng)更新圖標(biāo)樣式的實(shí)現(xiàn)方式

  • 自定義水波樣式的HUD的實(shí)現(xiàn)方式

接下來(lái)我們就對(duì)這三個(gè)內(nèi)容逐一進(jìn)行一下講解。


iOS中GIF動(dòng)圖的播放的實(shí)現(xiàn)方式

我們知道,在OC中展示靜態(tài)圖片我們是使用UIIamgeView的,然而UIImageView對(duì)GIF動(dòng)畫(huà)的展示卻并不友好。我知道你們一定會(huì)說(shuō)UIImageView不是有組動(dòng)畫(huà)么,老司機(jī)當(dāng)然知道有這個(gè)api,老司機(jī)最開(kāi)始也是用這個(gè)api,但是有的時(shí)候就會(huì)發(fā)現(xiàn)播放出的gif的節(jié)奏有可能會(huì)跟原圖不太一樣。這是為什么呢?原來(lái)這是因?yàn)镚IF文件的原因。我們知道,GIF其實(shí)就是由很多幀靜態(tài)圖片組成后連續(xù)播放組成的。重點(diǎn)就在于其實(shí)每一幀的時(shí)間是可以不一樣的。(雖然這樣的情況的確占少數(shù))其實(shí)這種情況還好一些,我們知道系統(tǒng)的組動(dòng)畫(huà)api是不支持動(dòng)畫(huà)的暫停與恢復(fù)的,而且當(dāng)圖片很多的時(shí)候也有很大的崩潰幾率,這是我們所不希望看見(jiàn)的,那么我們就開(kāi)始想自己寫(xiě)一個(gè)api讓他完美解決以上問(wèn)題?怎么做呢?

其實(shí)無(wú)非是UIImageView的圖片不斷切換,我自己加個(gè)定時(shí)器都可以。不過(guò)重要的還是一個(gè)思路。要想做到每一幀的時(shí)間可以不一樣長(zhǎng),我相信用定時(shí)器很難實(shí)現(xiàn)吧。這個(gè)時(shí)候,我們是否可以換個(gè)思路,記得CAAnimation中可以指定每種狀態(tài)時(shí)間的那個(gè)動(dòng)畫(huà)叫什么么還?對(duì)了,CAKeyframeAnimation。不記得了回頭看看這里的內(nèi)容

既然我們使用CAKeyframeAnimation的話,動(dòng)畫(huà)的暫停與恢復(fù)我們自然可以控制,只要控制好內(nèi)存也就可以解決崩潰問(wèn)題,那么這就是我們的思路了。

有了思路就方便很多了,接下來(lái)我們只要去實(shí)現(xiàn)就好了。我記得以為偉大的程序猿曾經(jīng)說(shuō)過(guò):

程序員最不怕的就是如何實(shí)現(xiàn),不會(huì)就去網(wǎng)上找,最怕的就是沒(méi)網(wǎng)和沒(méi)思路。 ------老司機(jī)

大體思路:

  • 解析GIF文件,獲取每一幀圖片及對(duì)應(yīng)時(shí)長(zhǎng)

  • 構(gòu)建CAKeyframeAnimation動(dòng)畫(huà),以layer的contents屬性去展示圖片

就這么簡(jiǎn)單的兩步。

老司機(jī)這里就不上全部代碼了,上一些核心的代碼簡(jiǎn)單的展示一下如何實(shí)現(xiàn):

展示GIF

以上就是核心代碼,其實(shí)每一句的目的都很簡(jiǎn)單,可能有些函數(shù)沒(méi)用過(guò)大家自己簡(jiǎn)單查一下也就都明白了。然后老司機(jī)放一下自己寫(xiě)的UIImageView的GIF分類,大家可以直接拿去用,在這里:

點(diǎn)我去下載

效果圖,中間是我點(diǎn)暫停了=。=

iOS系統(tǒng)更新圖標(biāo)樣式的實(shí)現(xiàn)方式

這個(gè)只得是什么呢?就是iOS中APP更新的時(shí)候在ICON上不是有一個(gè)更新的動(dòng)畫(huà)么?像下面這個(gè)樣子:

仿系統(tǒng)更新樣式

這里我們就針對(duì)這個(gè)動(dòng)畫(huà)的實(shí)現(xiàn)方式進(jìn)行一下探討。

說(shuō)實(shí)話拿到這個(gè)需求老司機(jī)第一反應(yīng)是CABasicAnimation。因?yàn)槲覀冎肋@個(gè)不規(guī)則的形狀我們完全可以使用CAShapeLayer去繪制(關(guān)于CoreAnimation中CALayer的個(gè)個(gè)子類老司機(jī)會(huì)在接下來(lái)的博客中逐一跟新,敬請(qǐng)期待)。不同的path可以繪制出不同的形狀,而且path屬性又是animutable的。貌似輕松地很。然而真正寫(xiě)了一下老司機(jī)發(fā)現(xiàn)自己還是太天真了,CABasicAnimation是基于始末狀態(tài)的補(bǔ)間動(dòng)畫(huà),然而老司機(jī)又根本拿不準(zhǔn)他自動(dòng)補(bǔ)充的計(jì)算方式,所以寫(xiě)出來(lái)的動(dòng)畫(huà)跟預(yù)期的總是有一定的差距,老司機(jī)的思路層一度陷入僵局。后來(lái)老司機(jī)換了一個(gè)思路,既然用不了補(bǔ)間動(dòng)畫(huà),我就一幀一幀畫(huà)吧。這里就用到了CADisplayLink(不熟悉的小伙伴來(lái)這里補(bǔ)票)。

大體思路:

  • 找出能代表動(dòng)畫(huà)中每一種狀態(tài)的path

  • 使用CADisplayLink反復(fù)繪制

首先我們找一下這個(gè)路徑要如何表示:

這里沒(méi)有什么訣竅啊,高中數(shù)學(xué)啊,就是硬畫(huà)啊,直接上代碼

路徑計(jì)算

這里屬性和參數(shù)老司機(jī)解釋一下self.sRadius是中間非暫停狀態(tài)下的扇形半徑。參數(shù)percent是將要繪制的路徑的角度百分比,suspendR是大家能看到暫停狀態(tài)下是從中心不斷擴(kuò)大一個(gè)圓的,suspendR就是當(dāng)前正要繪制的那個(gè)圓的半徑(注意并不是那個(gè)圓最終要變成的半徑,而是當(dāng)前的)。通過(guò)這三個(gè)變量老司機(jī)就能畫(huà)出這個(gè)指示器各個(gè)狀態(tài)的路徑。(是不是很膩害,畢竟數(shù)學(xué)課代表,嘖嘖嘖)

這里重點(diǎn)講的是動(dòng)畫(huà)的繪制,calayer的繪制老司機(jī)會(huì)在接下來(lái)的博客里面慢慢介紹,本例中用到的中空的layer使用了兩種繪制方式,usesEvenOddFillRulemask兩種,稍后放的demo里面會(huì)有具體代碼,大家看一下就好。

接下來(lái)就是使用CADisplayLink去一幀一幀繪制了,這也是上一期講過(guò)的內(nèi)容了,老司機(jī)也不廢話了,一切盡在demo吧:

點(diǎn)我去下載


自定義水波樣式的HUD的實(shí)現(xiàn)方式

閑的無(wú)聊寫(xiě)的一個(gè)效果,先看圖:

波浪指示器

其實(shí)這個(gè)效果還挺有意思的,那么如何實(shí)現(xiàn)呢?

其實(shí)有了上面的鋪墊你應(yīng)該會(huì)馬上反映出兩種思路:CAAnimation動(dòng)畫(huà)或者一幀一幀繪制。

這里老司機(jī)說(shuō)一句,本質(zhì)上,如果補(bǔ)間動(dòng)畫(huà)能完成效果的話,盡量使用CAAnimation,不用一幀幀繪制,代碼量少了,cpu壓力也小點(diǎn)。但是一般情況寫(xiě)復(fù)雜的補(bǔ)間動(dòng)畫(huà)都畫(huà)不出來(lái),比如說(shuō)這個(gè)。

我們還是分析一下需求,首先我們需要一條浪線,其次這條浪線還要能漲高。我們可以通過(guò)改變正弦曲線的相位來(lái)使波浪左右擺動(dòng)起來(lái),改變正弦曲線k值改變波浪的高度。(事實(shí)上老司機(jī)使用的是三次貝塞爾曲線模擬的正弦曲線,效果相似,只不過(guò)OC中沒(méi)有正弦曲線的封裝,想繪制正弦曲線的話會(huì)增加很多計(jì)算量)。

思路都在那,這個(gè)路徑的繪制代碼比較多,我就不截圖了,也是在demo中大家看一下就好,一步一步思路都很清晰,還有老司機(jī)一向是注釋詳細(xì)的,你懂我~

點(diǎn)我去下載


恩,這次主要是想給大家提供一下思路的擴(kuò)展,畢竟學(xué)會(huì)了動(dòng)畫(huà)要會(huì)用才是正道。

另外,我還要推薦老司機(jī)出品的DWAnimation,幫你清爽的生成CALayer的屬性動(dòng)畫(huà),并且任意拼接,組合~

優(yōu)雅么

gitHub下載地址:DWAnimation
歡迎給我star哦~

恩,轉(zhuǎn)載記得注明出處哦~

如果你覺(jué)得本篇文章對(duì)你有幫助,麻煩你給我點(diǎn)個(gè)贊!

如果你就喜歡老司機(jī)這墨跡勁你再加個(gè)關(guān)注!

如果你愛(ài)上老司機(jī)了你也可以給我打賞!

但是就算你給我打賞我也只賣藝,不賣身。

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

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

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