使用 CASpringAnimation 动画化 CAShapeLayer 路径
Animate CAShapeLayer path with CASpringAnimation
我有一个自定义 UIView
,我在其中添加了一个 CAShapeLayer
作为视图层的直接子层:
private let arcShapeLayer = CAShapeLayer()
CAShapeLayer
在 awakeFromNib
中声明了以下属性(边框是为了使动画更容易可视化):
arcShapeLayer.lineWidth = 2.0
arcShapeLayer.strokeColor = UIColor.black.cgColor
arcShapeLayer.fillColor = UIColor.lightGray.cgColor
arcShapeLayer.masksToBounds = false
layer.masksToBounds = false
layer.addSublayer(arcShapeLayer)
我在layoutSubviews
中声明arcShapeLayer
的框架:
arcShapeLayer.frame = layer.bounds
然后我有以下功能,我通过一定百分比(从ViewController
)以在一些拖动后实现弧形效果。简单的说我在层的底部加了一个quadCurve
:
func configureArcPath(curvePercentage: CGFloat) -> CGPath {
let path = UIBezierPath()
path.move(to: CGPoint.zero)
path.addLine(to:
CGPoint(
x: arcShapeLayer.bounds.minX,
y: arcShapeLayer.bounds.maxY
)
)
path.addQuadCurve(
to:
CGPoint(
x: arcShapeLayer.bounds.maxX,
y: arcShapeLayer.bounds.maxY
),
controlPoint:
CGPoint(
x: arcShapeLayer.bounds.midX,
y: arcShapeLayer.bounds.maxY + arcShapeLayer.bounds.maxY * (curvePercentage * 0.4)
)
)
path.addLine(to:
CGPoint(
x: arcShapeLayer.bounds.maxX,
y: arcShapeLayer.bounds.minY
)
)
path.close()
return path.cgPath
}
然后我尝试用下面的代码用spring效果弧制作动画:
func animateArcPath() {
let springAnimation = CASpringAnimation(keyPath: "path")
springAnimation.initialVelocity = 10
springAnimation.mass = 10
springAnimation.duration = springAnimation.settlingDuration
springAnimation.fromValue = arcShapeLayer.path
springAnimation.toValue = configureArcPath(curvePercentage: 0.0)
springAnimation.fillMode = .both
arcShapeLayer.add(springAnimation, forKey: nil)
arcShapeLayer.path = configureArcPath(curvePercentage: 0.0)
}
正如您在视频中看到的那样,问题是 电弧永远不会超过 。虽然它在原始位置和静止位置之间摆动,但从未达到 spring 效果。
我在这里错过了什么?
我试过这个,我可以报告你是完全正确的。它与零位钳位无关。可见动画夹在 两个 极端。
假设您提供了一个很大的质量值,这样超调应该会越过凸弓的初始位置 在其 return 旅程中 回到起点.然后我们看到的是动画将 both 夹在原始位置 and 上,您尝试将其设置为最小值。当 spring 在它们之间摆动时,我们看到动画在一个极端和另一个极端之间发生,但当它达到最大值或最小值时,它只是固定在那里,直到它有时间摆动到最大程度并且 return.
我不得不得出结论,CAShapeLayer path
不喜欢 springing 动画。 CAShapeLayer path spring animation not 'overshooting'
提出了同样的观点
我能够通过链接正常的基本动画来模拟您可能想要的那种外观:
这是我使用的代码(基于你自己的代码):
@IBAction func animateArcPath() {
self.animate(to:-1, in:0.5, from:arcShapeLayer.path!)
}
func animate(to arc:CGFloat, in time:Double, from current:CGPath) {
let goal = configureArcPath(curvePercentage: arc)
let anim = CABasicAnimation(keyPath: "path")
anim.duration = time
anim.fromValue = current
anim.toValue = goal
anim.delegate = self
anim.setValue(arc, forKey: "arc")
anim.setValue(time, forKey: "time")
anim.setValue(goal, forKey: "pathh")
arcShapeLayer.add(anim, forKey: nil)
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let arc = anim.value(forKey:"arc") as? CGFloat,
let time = anim.value(forKey:"time") as? Double,
let p = anim.value(forKey:"pathh") {
if time < 0.05 {
return
}
self.animate(to:arc*(-0.5), in:time*0.5, from:p as! CGPath)
}
}
我有一个自定义 UIView
,我在其中添加了一个 CAShapeLayer
作为视图层的直接子层:
private let arcShapeLayer = CAShapeLayer()
CAShapeLayer
在 awakeFromNib
中声明了以下属性(边框是为了使动画更容易可视化):
arcShapeLayer.lineWidth = 2.0
arcShapeLayer.strokeColor = UIColor.black.cgColor
arcShapeLayer.fillColor = UIColor.lightGray.cgColor
arcShapeLayer.masksToBounds = false
layer.masksToBounds = false
layer.addSublayer(arcShapeLayer)
我在layoutSubviews
中声明arcShapeLayer
的框架:
arcShapeLayer.frame = layer.bounds
然后我有以下功能,我通过一定百分比(从ViewController
)以在一些拖动后实现弧形效果。简单的说我在层的底部加了一个quadCurve
:
func configureArcPath(curvePercentage: CGFloat) -> CGPath {
let path = UIBezierPath()
path.move(to: CGPoint.zero)
path.addLine(to:
CGPoint(
x: arcShapeLayer.bounds.minX,
y: arcShapeLayer.bounds.maxY
)
)
path.addQuadCurve(
to:
CGPoint(
x: arcShapeLayer.bounds.maxX,
y: arcShapeLayer.bounds.maxY
),
controlPoint:
CGPoint(
x: arcShapeLayer.bounds.midX,
y: arcShapeLayer.bounds.maxY + arcShapeLayer.bounds.maxY * (curvePercentage * 0.4)
)
)
path.addLine(to:
CGPoint(
x: arcShapeLayer.bounds.maxX,
y: arcShapeLayer.bounds.minY
)
)
path.close()
return path.cgPath
}
然后我尝试用下面的代码用spring效果弧制作动画:
func animateArcPath() {
let springAnimation = CASpringAnimation(keyPath: "path")
springAnimation.initialVelocity = 10
springAnimation.mass = 10
springAnimation.duration = springAnimation.settlingDuration
springAnimation.fromValue = arcShapeLayer.path
springAnimation.toValue = configureArcPath(curvePercentage: 0.0)
springAnimation.fillMode = .both
arcShapeLayer.add(springAnimation, forKey: nil)
arcShapeLayer.path = configureArcPath(curvePercentage: 0.0)
}
正如您在视频中看到的那样,问题是 电弧永远不会超过 。虽然它在原始位置和静止位置之间摆动,但从未达到 spring 效果。
我在这里错过了什么?
我试过这个,我可以报告你是完全正确的。它与零位钳位无关。可见动画夹在 两个 极端。
假设您提供了一个很大的质量值,这样超调应该会越过凸弓的初始位置 在其 return 旅程中 回到起点.然后我们看到的是动画将 both 夹在原始位置 and 上,您尝试将其设置为最小值。当 spring 在它们之间摆动时,我们看到动画在一个极端和另一个极端之间发生,但当它达到最大值或最小值时,它只是固定在那里,直到它有时间摆动到最大程度并且 return.
我不得不得出结论,CAShapeLayer path
不喜欢 springing 动画。 CAShapeLayer path spring animation not 'overshooting'
我能够通过链接正常的基本动画来模拟您可能想要的那种外观:
这是我使用的代码(基于你自己的代码):
@IBAction func animateArcPath() {
self.animate(to:-1, in:0.5, from:arcShapeLayer.path!)
}
func animate(to arc:CGFloat, in time:Double, from current:CGPath) {
let goal = configureArcPath(curvePercentage: arc)
let anim = CABasicAnimation(keyPath: "path")
anim.duration = time
anim.fromValue = current
anim.toValue = goal
anim.delegate = self
anim.setValue(arc, forKey: "arc")
anim.setValue(time, forKey: "time")
anim.setValue(goal, forKey: "pathh")
arcShapeLayer.add(anim, forKey: nil)
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let arc = anim.value(forKey:"arc") as? CGFloat,
let time = anim.value(forKey:"time") as? Double,
let p = anim.value(forKey:"pathh") {
if time < 0.05 {
return
}
self.animate(to:arc*(-0.5), in:time*0.5, from:p as! CGPath)
}
}