gpt4 book ai didi

ios - 具有动画路径内容的 CALayer,使可检查/可设计

转载 作者:行者123 更新时间:2023-11-29 11:51:32 24 4
gpt4 key购买 nike

我通过子类化 UIView 创建了一个自定义的循环进度 View ,将 CAShapeLayer 子层添加到其层并覆盖 drawRect() 以更新形状层的 path 属性。

通过使 View @IBDesignableprogress 属性 @IBInspectable,我能够在 Interface Builder 中编辑它的值并查看实时更新贝塞尔曲线路径。不是必需的,但真的很酷!

接下来,我决定制作路径动画:每当您在代码中设置一个新值时,表示进度的圆弧应该从零长度“增长”到圆的任何百分比(想想 Activity 应用程序中的圆弧)在 Apple Watch 中)。

为了实现这一点,我将我的 CAShapeLayer 子层替换为自定义 CALayer 子类,该子类具有 @dynamic (@NSManaged) 属性,观察为动画的关键(我实现了 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 中显示我的路径

我试过像这样实现我的 View 的 prepareForInterfaceBuilder():

override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()

self.topLabel.text = "Hello, Interface Builder!"
updateArcLayer()
}

...并且标签文本更改反射(reflect)在 Interface Builder 中,但路径未呈现。

我错过了什么吗?

最佳答案

好吧,这不是很有趣吗...原来我的 @Inspectable 属性的声明有一个非常愚蠢的错误。

你能发现吗?

@IBInspectable var currentValue: CGFloat {
set(newValue) {
setValue(newValue: currentValue, animated: false)
self.setNeedsLayout()
}
get {
return progress
}
}

应该是:

@IBInspectable var currentValue: CGFloat {
set(newValue) {
setValue(newValue: newValue, animated: false)
self.setNeedsLayout()
}
get {
return progress
}
}

也就是说,我丢弃了传递的值 (newValue) 并使用当前值 (currentValue) 来设置内部变量。将值(始终为 0.0)“记录”到 Interface Builder(通过我标签的 text 属性!)给了我一个线索。

现在它工作正常,不需要 drawRect()

关于ios - 具有动画路径内容的 CALayer,使可检查/可设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40930273/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com