如何解决Cocoa中移除子视图时的动画异常问题
解决NSView淡出动画后短暂闪回再移除的问题
问题根源
你使用的CABasicAnimation属于CALayer层级的动画,它仅修改图层的视觉表现,不会改变图层的实际opacity属性值。动画结束后,图层会自动恢复到初始的opacity(1.0),这就导致回调执行前视图短暂闪回显示。
解决方案
方案一:修正CALayer动画的属性同步
在添加动画前,先将图层的实际opacity设置为目标值(0.0),同时配置动画的fillMode和isRemovedOnCompletion,确保动画结束后不会恢复初始状态:
修改你的fadeAnimation扩展:
extension NSView { func fadeAnimation(callBack: @escaping () -> Void) { guard let layer = self.layer else { return } // 先设置图层实际opacity为0,避免动画结束后闪回 layer.opacity = 0.0 let animation = CABasicAnimation(keyPath: "opacity") animation.delegate = CustomCAAnimationDelegate(callBack: callBack) animation.duration = 2.0 animation.fromValue = 1.0 animation.toValue = 0.0 animation.timingFunction = CAMediaTimingFunction(name: .linear) // 保持动画结束后的状态 animation.fillMode = .forwards animation.isRemovedOnCompletion = false layer.add(animation, forKey: "fadeOutAnimation") } }
同时简化回调逻辑(无需再设置alphaValue):
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { blueView.fadeAnimation(callBack: { print("Done!") blueView.removeFromSuperview() }) }
方案二:使用AppKit原生NSView动画API(推荐)
直接使用NSAnimationContext来执行视图动画,这种方式会自动同步视图的alphaValue属性,完全避免闪回问题,代码也更简洁:
替换原有的DispatchQueue回调代码:
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { NSAnimationContext.runAnimationGroup({ context in context.duration = 2.0 context.timingFunction = CAMediaTimingFunction(name: .linear) // 使用animator()来触发AppKit动画 blueView.animator().alphaValue = 0.0 }, completionHandler: { print("Done!") blueView.removeFromSuperview() }) }
这种方式不需要额外的CustomCAAnimationDelegate和扩展,完全遵循AppKit的动画机制,稳定性更好。
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

