#82 利用 CABasicAnimation & CAShapeLayer 繪製線條動畫
利用 CAShapeLayer & UIBezierPath 我們可以繪製線條,不過不僅於此,當我們結合 CABasicAnimation 時,我們還能讓它變成小畫家,以生動的動畫一筆一劃繪製線條呢。
比方我們可參考以下連結 Ting 同學繪製的 Apple,一筆一劃畫出美味的蘋果咬一口。
接下來就讓我們示範如何利用 CABasicAnimation 繪製帥氣的勾勾吧。
以 CAShapeLayer 繪製帥氣的勾勾
override func viewDidLoad() {
super.viewDidLoad()
let path = UIBezierPath()
var point = CGPoint(x: 10, y: 260)
path.move(to: point)
point = CGPoint(x: 60, y: 300)
path.addLine(to: point)
point = CGPoint(x: 140, y: 160)
path.addLine(to: point)
let checkmarkLayer = CAShapeLayer()
checkmarkLayer.path = path.cgPath
checkmarkLayer.lineWidth = 5
checkmarkLayer.strokeColor = UIColor.red.cgColor
checkmarkLayer.fillColor = nil
view.layer.addSublayer(checkmarkLayer)
}
關於如何利用 CAShapeLayer & UIBezierPath 繪製線條,相關說明可參考以下連結的方法 2,addSublayer。
若想查詢線條的座標位置,可將圖片上傳到網站 iview,參考以下連結的教學。
使用 CABasicAnimation 設定動畫
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 5
checkmarkLayer.add(animation, forKey: nil)
結果
說明:
let animation = CABasicAnimation(keyPath: "strokeEnd")
CABasicAnimation 可以實現許多動畫效果,比方透明度的變化,位置大小的變化等,而動畫的效果則由我們生成 CABasicAnimation 時傳入的 keyPath 決定。此處我們傳入 strokeEnd,實現從 CABasicAnimation 路徑的起點畫線到終點的動畫效果。
animation.fromValue = 0
animation.toValue = 1
控制動畫從哪裡開始跟結束。我們的動畫將作用於 CAShapeLayer,fromValue 設為 0 表示它將從 CAShapeLayer 路徑的起點開始,toValue 設為 1 表示動畫將在畫到路徑終點時結束。
讓我們調整一下數值,進一步了解它的作用。比方我們將 fromValue 設為 0.2, toValue 設為 0.8,此時將如下圖,動畫在線條已經畫了一部分時才開始,在還沒畫到終點時動畫就被狠心地終止了。
animation.fromValue = 0.2
animation.toValue = 0.8
animation.duration = 5
設定動畫的時間,以秒為單位。
checkmarkLayer.add(animation, forKey: nil)
將動畫加到 CAShapeLayer 上,實現繪製 CAShapeLayer 線條的動畫效果。
了解基本的動畫繪製方法後,接下來我們改用一開始 Ting 同學繪製的 Apple 為例,進一步說明其它進階的效果。
動畫的速度
設定 timingFunction 調整動畫的速度,比方 easeInEaseOut 表示一開始比較慢,過程中逐漸加速,接近結尾時再放慢速度。
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
關於其它可設定的速度名字,可參考以下連結。
橡皮擦清除線條的動畫效果
生成 CABasicAnimation 時傳入 strokeStart 將實現橡皮擦清除線條的動畫效果。
let animation = CABasicAnimation(keyPath: "strokeStart")
如下圖所示,一開始 Apple 會先完整呈現,然後再照著當初繪製路徑的順序消除。
重覆的動畫
CABasicAnimation 的 repeatCount 可以控制動畫重覆的次數,比方 2 表示動畫將重覆兩次。那如果希望動畫永遠不要停,一直到世界末日呢 ?
沒問題,只要設定 Float.greatestFiniteMagnitude 即可 !
animation.repeatCount = .greatestFiniteMagnitude
比方以下為永不結束的畫圓(ring)動畫,半夜睡不著時可以看著它幫助入眠。
let circlePath = UIBezierPath(roundedRect: CGRect(x: 50, y: 100, width: 100, height: 100), cornerRadius: 50)
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
circleLayer.lineWidth = 5
circleLayer.strokeColor = UIColor.red.cgColor
circleLayer.fillColor = nil
view.layer.addSublayer(circleLayer)
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 1.5
animation.repeatCount = .greatestFiniteMagnitude
circleLayer.add(animation, forKey: nil)
動畫結束時執行的程式
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let path = UIBezierPath()
var point = CGPoint(x: 10, y: 260)
path.move(to: point)
point = CGPoint(x: 60, y: 300)
path.addLine(to: point)
point = CGPoint(x: 140, y: 160)
path.addLine(to: point)
path.close()
let checkmarkLayer = CAShapeLayer()
checkmarkLayer.path = path.cgPath
checkmarkLayer.lineWidth = 5
checkmarkLayer.strokeColor = UIColor.red.cgColor
checkmarkLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(checkmarkLayer)
CATransaction.begin()
CATransaction.setCompletionBlock {
checkmarkLayer.fillColor = UIColor.blue.cgColor
}
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 5
checkmarkLayer.add(animation, forKey: nil)
CATransaction.commit()
}
利用 CATransaction.setCompletionBlock 設定動畫結束時執行的程式,在將整個動畫的程式包在 CATransaction.begin() & CATransaction.commit() 之間。
文字動畫
參考 Yuki 同學繪製的文字動畫。