iOS CAShapeLayer、CADisplayLink 實現波浪動畫效果


iOS CAShapeLayer、CADisplayLink 實現波浪動畫效果

效果圖

代碼已上傳 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo

可以自定義波浪高度、寬度、速度、方向、漸變速度、水的深度等參數。

實現原理

波浪的形狀繪制在 CAShapeLayer 上。通過 CADisplayLink 與屏幕刷新頻率同步,每次刷新都繪制新的波浪,並改變小船的位置和角度。另外,水和天空的顏色是漸變的,由 CAGradientLayer 實現,其中,顯示水的 CAGradientLayer 需要有波浪形狀的 CAShapeLayer 的遮罩(mask)。

CAShapeLayer

CAShapeLayer 的屬性 path (CGPath)就是圖層要顯示的形狀。把波浪的形狀繪制出來,賦值給此屬性即可。

創建 CADisplayLink,相應的 target 實現屏幕刷新時要調用的方法。把 CADisplayLink 加入 RunLoop 中。通過 isPaused 屬性控制 CADisplayLink 是否暫停(target 是否調用方法)

private var waveLink: CADisplayLink?
waveLink = CADisplayLink(target: self, selector: #selector(waveLinkRefresh))
waveLink?.isPaused = true
waveLink?.add(to: .current, forMode: .defaultRunLoopMode)

繪制波浪

波浪的形狀關鍵是正弦函數曲線

y = A * sin(x + B)

參數 A 決定了波浪的高度;參數 B 決定了波浪在 x 軸的位置。

用一個屬性 currentPhase 表示參數 B

private var currentPhase: CGFloat = 0

每次屏幕刷新的時候用 currentPhase 繪制,然后更新此屬性,加上一個固定的數。這樣波浪就會朝左或右勻速移動。

為了使波浪高度逐漸變化,用一個屬性表示參數 A,然后每次繪制后更新此屬性,加上一個固定的數,直到波浪高度達到目標值。

小船的位置和旋轉角度

已知小船 x 軸坐標,通過正弦函數可以直接計算出小船的 y 軸坐標。此外,小船需要隨着波浪旋轉,旋轉至船底與波浪表面相切。這就要對正弦函數進行求導

y' = A * cos(x + B)

用以上式子計算出小船所在位置的 y',表示正弦函數在此處的切線斜率,幾何意義是切線與 x 軸的夾角的正切值。反正切即可求出切線與 x 軸的夾角,也就是小船需要旋轉的角度

angle = atan(y')

用以上旋轉角度,改變小船視圖(UIView)的 transform,調用 CGAffineTransform 的 rotated(by:) 方法,實現小船的旋轉。

CAGradientLayer

CAGradientLayer 默認的顏色漸變方向是由上至下。給 colors 屬性賦值一個包含 CGColor 的數組,則圖層顏色由上至下,從數組第一個值經中間值漸變至最后一個值。

顯示水的 CAGradientLayer 需要呈現波浪形狀,需要 CAShapeLayer 的遮罩。把繪制好波浪形狀的 CAShapeLayer 賦值給 CAGradientLayer 的 mask 屬性即可。

以上是動畫效果的實現原理,具體見 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo

轉載請注明出處:http://www.cnblogs.com/silence-cnblogs/p/6979418.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM