提问人:cool8jay 提问时间:5/9/2023 最后编辑:cool8jay 更新时间:5/9/2023 访问量:89
如何通过动画围绕某个点旋转 CAShapeLayer?
How to rotate a CAShapeLayer around some point with animation?
问:
自定义视图包含一些 CALayer 作为其内容。
我想为红线添加一致的旋转动画。(把它想象成一个模拟时钟的指针)
预期结果:红线在蓝色方块的中心旋转。
当前结果:红线在蓝色方块的左下角旋转。请参阅下面的 gif。
红线的动画代码为:
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
// Set animation properties
rotationAnimation.fromValue = CGFloat.pi * 2.0
rotationAnimation.toValue = 0
rotationAnimation.duration = 2.0
rotationAnimation.isCumulative = true
rotationAnimation.repeatCount = Float.greatestFiniteMagnitude
// Add rotation animation to pointer layer
pointerLayer.add(rotationAnimation, forKey: "rotationAnimation")
完整的项目在这里:
https://github.com/cool8jay/public/files/11426695/testDrawPointer.zip
以下是我在谷歌或stackoverflow在线后尝试过的内容:
- 更改 anchorPoint
- 使用 CATransform3D
- 使用 CGAffineTransform
- 以上组合
没有一个对我有用。
答:
1赞
ix4n33
5/9/2023
#1
您忘记设置图层的框架,将这些行添加到您的代码中,它将起作用:
borderLayer.frame = bounds
pointerLayer.frame = borderLayer.bounds
Leo的回答也有效。您看到红色指针拉长蓝色边框的原因是,您使用的颜色和形状,结合描边线的平行绘制和边界剪裁,很容易产生视错觉。所以它看起来没有围绕中心旋转,但实际上它确实如此。
以下是完整代码:
class ClockView: NSView {
let pointerLayer = CAShapeLayer()
let borderLayer = CAShapeLayer()
override public init(frame frameRect: NSRect) {
super.init(frame: frameRect)
setup()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
self.wantsLayer = true
borderLayer.frame = bounds
borderLayer.fillColor = NSColor.gray.cgColor
borderLayer.path = CGPath(ellipseIn: borderLayer.bounds, transform: nil)
layer?.addSublayer(borderLayer)
let path = CGMutablePath()
path.move(to: CGPointMake(bounds.midX, bounds.midY))
path.addLine(to: CGPointMake(bounds.midX + 50, bounds.midY))
pointerLayer.path = path
pointerLayer.frame = bounds
pointerLayer.lineWidth = 8
pointerLayer.strokeColor = NSColor.red.cgColor
layer?.addSublayer(pointerLayer)
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.fromValue = CGFloat.pi * 2
animation.toValue = 0
animation.duration = 8
animation.isCumulative = true
animation.repeatCount = Float.greatestFiniteMagnitude
pointerLayer.add(animation, forKey: "rotationAnimation")
}
}
我将 borderLayer 的形状更改为圆形,去掉线条描边,并将颜色更改为最不刺眼的颜色。
我还重新排列了代码,使其更易于阅读。
评论