CADisplayLink 動(dòng)畫進(jìn)階

CADisplayLink 動(dòng)畫進(jìn)階

前言

  • 之前有更新過一篇 如何實(shí)現(xiàn)一個(gè)圓形進(jìn)度條按鈕 的文章。其需求場(chǎng)景是適應(yīng)于相機(jī)拍照錄制按鈕的,主要介紹的是如何使用 CADisplayLink 實(shí)現(xiàn)其進(jìn)度條的動(dòng)畫效果。然而,寫的比較粗糙,沒有封裝也沒有整理代碼,僅僅提供實(shí)現(xiàn),dbq。于是在處女座強(qiáng)迫癥以及愧疚感的驅(qū)使下,最近又重新對(duì)該 demo 進(jìn)行了整理。

  • 在這篇博客你可以了解到的內(nèi)容有:

    1. 如何基于 CADisplayLink 實(shí)現(xiàn)非線性動(dòng)畫效果
    2. 什么是緩動(dòng)函數(shù)
  • 實(shí)現(xiàn)的效果舉例:


    QQ20190217-141333.gif

正文

需求分析

  • 做任何動(dòng)畫效果,首先要做的就是對(duì)動(dòng)畫的需求進(jìn)行拆分,比如整個(gè)動(dòng)畫的過程可以分為哪幾個(gè)部分。針對(duì)本文中要實(shí)現(xiàn)的圓形進(jìn)度條按鈕動(dòng)畫來說,整個(gè)動(dòng)畫過程可以拆分為按鈕放大的動(dòng)畫以及進(jìn)度條擴(kuò)充動(dòng)畫兩部分。

    對(duì)于按鈕放大的過程,需要考慮的是在放大前到放大之后的狀態(tài),按鈕中有哪些部分發(fā)生了變化,如何發(fā)生變化,是線性過渡還是非線性過渡?

    對(duì)于進(jìn)度條擴(kuò)充部分,考慮的就是黃色進(jìn)度條是如何過渡狀態(tài)的,線性還是非線性?

    顯然之前的按鈕動(dòng)畫效果都是線性效果,什么是線性,就是 y = ax + b,動(dòng)畫過程是均勻變化的。非線性就是動(dòng)畫過程是根據(jù)某個(gè)函數(shù)進(jìn)行非均勻的變化。

如何基于 CADisplayLink 實(shí)現(xiàn)非線性動(dòng)畫效果

在介紹實(shí)現(xiàn)非線性動(dòng)畫效果之前,我們先簡(jiǎn)單復(fù)習(xí)一下線性動(dòng)畫效果的實(shí)現(xiàn)。假設(shè)動(dòng)畫的起始狀態(tài)變量為 fromValue,最終狀態(tài)的變量為 toValue,當(dāng)前動(dòng)畫值進(jìn)度為 percent,當(dāng)前狀態(tài)為 currentValue。那么我們可以得到計(jì)算動(dòng)畫當(dāng)前狀態(tài)的插值公式為:

currentValue = fromValue + (toValue - fromValue) * percent 

其實(shí)整體實(shí)現(xiàn)思路還是和 如何實(shí)現(xiàn)一個(gè)圓形進(jìn)度條按鈕 中提到的一樣。不過在這里有需要勘誤的一個(gè)點(diǎn)是,上篇博客提到 CADisplaylink "iOS 設(shè)備屏幕顯示每秒刷新60次"。CADisplayLink 的刷新頻率確實(shí)是60次/秒左右,但是并不固定,由于每次調(diào)用 CADisplayLink 的時(shí)間間隔都不是平均的,所以我們不能根據(jù)調(diào)用次數(shù)乘以1/60的時(shí)間間隔來得到當(dāng)前經(jīng)歷的時(shí)間。正確計(jì)算當(dāng)前經(jīng)歷時(shí)間的方法是通過獲取當(dāng)前時(shí)間再減去起始時(shí)間來得到:

@property (nonatomic, assign) NSTimeInterval beginTime;
@property (nonatomic, assign) NSTimeInterval currentTime;
//在動(dòng)畫開始時(shí)記錄起始時(shí)間
self.beginTime = CACurrentMediaTime();

得到當(dāng)前的經(jīng)歷時(shí)間為

self.currentTime = CACurrentMediaTime() - self.beginTime;

由于我們是線性動(dòng)畫,所以假設(shè)動(dòng)畫時(shí)間進(jìn)程為 timePercent,timePercent = self.currentTime / duration,那么當(dāng)前動(dòng)畫值進(jìn)度 percent 就等于 timePercent,然后可以得到

currentValue = fromValue + (toValue - fromValue) * (self.currentTime / duration) 

其中 fromValue、toValue、duration 都是已知數(shù),這樣我們就可以拿到 currentValue,然后在 CADisplayLink 每次調(diào)用的函數(shù)中去更新 currentValue 值,就可以實(shí)現(xiàn)線性動(dòng)畫的過渡效果了。

基于此思路我們實(shí)現(xiàn)一個(gè)插值函數(shù)如下,percent 為動(dòng)畫值進(jìn)度

- (CGFloat)interpolateFrom:(CGFloat)from to:(CGFloat)to percent:(CGFloat)percent {
    return from + (to - from) * percent;
}

那么,如何實(shí)現(xiàn)非線性的動(dòng)畫效果呢? 我們先了解一下一些實(shí)現(xiàn)非線性動(dòng)畫效果的函數(shù) —— 緩動(dòng)函數(shù)

緩動(dòng)函數(shù)

緩動(dòng)函數(shù)是動(dòng)畫時(shí)間進(jìn)程(p)和動(dòng)畫值進(jìn)程(s)之間的一個(gè)映射。什么是動(dòng)畫時(shí)間進(jìn)程,就是 timePercent,而動(dòng)畫值進(jìn)程就是 percent。兩者的定義閾都為[0,1]。在線性關(guān)系中,percent = timePercent,而在非線性關(guān)系中,percent = f(timePercent)。

我們知道動(dòng)畫一般都有漸進(jìn)(EaseIn)、漸出(EaseOut)、漸近漸出(EaseInOut)的效果,它們對(duì)應(yīng)的緩動(dòng)函數(shù)圖大概是這樣:


function.png

舉例來說,對(duì)于 EaseIn 函數(shù)的圖像分析,y = x * x 的坐標(biāo)圖是完全符合 EaseIn 的效果的,所以我們可以實(shí)現(xiàn)一個(gè) y = x * x 的函數(shù)作為這種 EaseIn 效果的緩動(dòng)函數(shù):

- (double)calculate:(double) p {
    return p * p;
}

那么,在線性動(dòng)畫的代碼中,調(diào)用 interpolateFrom:to:percent: 之前,將 percent(其實(shí)是 timePercent)作為參數(shù)傳入 calculate 方法,計(jì)算得到動(dòng)畫值進(jìn)程 percent,然后再調(diào)用 interpolateFrom:to:percent: 計(jì)算當(dāng)前的動(dòng)畫值。這樣我們就實(shí)現(xiàn)了非線性動(dòng)畫中的 QuadraticEaseIn 動(dòng)畫。

關(guān)于各種緩動(dòng)函數(shù)的效果可以參照這個(gè)網(wǎng)址,對(duì)于其中所有效果的緩動(dòng)函數(shù)都已經(jīng)在 Demo KiraCircleButton 中的 AnimationFunction 中實(shí)現(xiàn)了。Demo 中提供了配置頁面,可以方便的選擇配置體驗(yàn)不同的動(dòng)畫效果。

既然本文是進(jìn)階篇,那么我就不貼具體的實(shí)現(xiàn)代碼了。其中有關(guān)如何繪制,具體如何實(shí)現(xiàn)動(dòng)畫的問題,可以直接下載 Demo KiraCircleButton 看源碼。
有問題歡迎指出,謝謝。

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,102評(píng)論 4 61
  • 【Android 動(dòng)畫】 動(dòng)畫分類補(bǔ)間動(dòng)畫(Tween動(dòng)畫)幀動(dòng)畫(Frame 動(dòng)畫)屬性動(dòng)畫(Property ...
    Rtia閱讀 6,373評(píng)論 1 38
  • 人生就是這樣了,他們年輕的時(shí)候,你我都年輕。他們老時(shí),我們也老了。一日到市里辦事,辦得很順利就早些回了家。在路的拐...
    夏未未閱讀 763評(píng)論 0 1
  • “睡前吃一個(gè)蘋果,醫(yī)生就會(huì)丟飯碗”這句話出現(xiàn)在1866年2月出版的《備忘和查詢》中,這個(gè)有一些夸張的的諺語一直被引...
    湖南籍心曠神怡閱讀 406評(píng)論 0 0
  • 對(duì)于已創(chuàng)建的Docker Machine實(shí)例,更換鏡像源的方法如下 Docker Toolbox 1,在windo...
    whitemon閱讀 660評(píng)論 0 0

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