如何移除CALayer的隐式动画?绘图App鼠标交互问题
如何禁用CALayer重绘时的隐式动画?
你遇到的问题是CALayer在重绘时触发了隐式动画,导致旧的"+"标记逐渐淡出。之前尝试的方法无效,是因为没有找对禁用隐式动画的正确时机或方式,以下是两种有效的解决方案:
方案一:在触发重绘时禁用CATransaction动作
隐式动画是在setNeedsDisplay触发layer更新时自动创建的,所以需要在调用setNeedsDisplay的代码外层包裹CATransaction并禁用动作:
修改MyLayer中的drawLines方法:
func drawLines(at pos : CGPoint){ self.pos = pos CATransaction.begin() CATransaction.setDisableActions(true) setNeedsDisplay() CATransaction.commit() }
方案二:重写CALayer的action(forKey:)方法彻底禁用隐式动画
通过重写该方法,返回nil可以阻止layer为任何属性变化创建隐式动画,也可以针对特定key(比如display)禁用:
在MyLayer中添加以下方法:
override func action(forKey event: String) -> CAAction? { // 禁用所有隐式动画 return nil // 仅禁用重绘相关的动画,保留其他属性的隐式动画 // if event == "display" { // return nil // } // return super.action(forKey: event) }
为什么之前的方法无效?
- 你之前把
CATransaction包裹在绘图代码里,但draw(in:)是系统在重绘阶段调用的,此时CATransaction的作用域已经无法影响隐式动画的创建。 removeAllAnimations只能移除已添加的显式动画,而隐式动画是每次layer更新时自动生成的,所以无法通过这个方法阻止其出现。
修改后的完整MyLayer示例(二选一即可):
class MyLayer : CALayer { var pos : CGPoint? override func draw(in ctx: CGContext) { guard let pos = pos else {return} ctx.setStrokeColor(.black) let vline = NSBezierPath() vline.move(to: .init(x: 0, y: pos.y)) vline.line(to: .init(x: bounds.width, y: pos.y)) vline.lineWidth = 2 let hline = NSBezierPath() hline.move(to: .init(x: pos.x, y: 0)) hline.line(to: .init(x: pos.x, y: bounds.height)) hline.lineWidth = 2 ctx.addPath(vline.cgPath) ctx.addPath(hline.cgPath) ctx.strokePath() } func drawLines(at pos : CGPoint){ self.pos = pos CATransaction.begin() CATransaction.setDisableActions(true) setNeedsDisplay() CATransaction.commit() } // 可选:用action(forKey:)替代上述CATransaction代码 // override func action(forKey event: String) -> CAAction? { // return nil // } }
内容的提问来源于stack exchange,提问作者Mattia Marini
相关产品推荐
相关产品推荐

