我通過繼承UIView
,加入CAShapeLayer
子層的層和壓倒一切的drawRect()
更新的形狀層的path
財產一個定製的圓形進度視圖。的CALayer與動畫路徑內容,請檢查的/設計性
通過使視圖@IBDesignable
和progress
屬性@IBInspectable
,我能夠在Interface Builder中編輯它的值,並實時查看更新的貝塞爾路徑。非必要的,但非常酷!
接下來,我決定讓路徑變成動畫:無論您何時在代碼中設置一個新值,指示進度的弧線應該從零長度「增長」到達到圓的任何百分比(考慮活動中的弧線蘋果手錶應用程序)。
要做到這一點,我通過一個定製CALayer
子類具有@dynamic
(@NSManaged
)特性,觀察到與ananimation鍵換我CAShapeLayer
子(我實現needsDisplayForKey()
,actionForKey()
,drawInContext()
等)。
我查看代碼(相關部分)看起來是這樣的:
// Triggers path update (animated)
private var progress: CGFloat = 0.0 {
didSet {
updateArcLayer()
}
}
// Programmatic interface:
// (pass false to achieve immediate change)
func setValue(newValue: CGFloat, animated: Bool) {
if animated {
self.progress = newValue
} else {
arcLayer.animates = false
arcLayer.removeAllAnimations()
self.progress = newValue
arcLayer.animates = true
}
}
// Exposed to Interface Builder's inspector:
@IBInspectable var currentValue: CGFloat {
set(newValue) {
setValue(newValue: currentValue, animated: false)
self.setNeedsLayout()
}
get {
return progress
}
}
private func updateArcLayer() {
arcLayer.frame = self.layer.bounds
arcLayer.progress = progress
}
而且層代碼:
var animates: Bool = true
@NSManaged var progress: CGFloat
override class func needsDisplay(forKey key: String) -> Bool {
if key == "progress" {
return true
}
return super.needsDisplay(forKey: key)
}
override func action(forKey event: String) -> CAAction? {
if event == "progress" && animates == true {
return makeAnimation(forKey: event)
}
return super.action(forKey: event)
}
override func draw(in ctx: CGContext) {
ctx.beginPath()
// Define the arcs...
ctx.closePath()
ctx.setFillColor(fillColor.cgColor)
ctx.drawPath(using: CGPathDrawingMode.fill)
}
private func makeAnimation(forKey event: String) -> CABasicAnimation? {
let animation = CABasicAnimation(keyPath: event)
if let presentationLayer = self.presentation() {
animation.fromValue = presentationLayer.value(forKey: event)
}
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
animation.duration = animationDuration
return animation
}
的動畫作品,但現在我可以」讓我的路徑顯示在Interface Builder中。
我試圖實現我的觀點的prepareForInterfaceBuilder()
這樣的:
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.topLabel.text = "Hello, Interface Builder!"
updateArcLayer()
}
...和標籤文本的變化體現在界面生成器,但路徑不會被渲染。
我錯過了什麼嗎?
的drawRect()是核心動畫的存在的禍根。它應該與那些使用Core Graphics的人分離,並且在使用Core Animation的各個方面都受到影響。做得好! – Confused