iOS动画流程实现:应编写哪些完成处理程序?
嘿,我太懂这种“懂原理但不知道怎么落地”的感觉了!刚好你这个嵌套VC+SpriteKit动画的场景非常典型,我来给你把代码里的???填上,同时完美实现「提前准备动画+按顺序执行」的需求。
首先明确核心思路:我们用串行队列处理动画资源的提前准备(避免阻塞主线程),同时用SpriteKit的动作完成回调保证动画顺序执行——前一个动画跑完再启动下一个,而且在前一个动画运行时,后台已经在准备下一个动画的资源了。
假设你的AnimationVC基础代码框架是这样的,我直接补全???内容,再给你拆解每个部分的作用:
import SpriteKit class AnimationVC: UIViewController { @IBOutlet weak var skView: SKView! private var currentScene: SKScene! // ??? 这里需要工具管理动画顺序和后台准备 // 👇 补全:串行队列,保证准备工作按顺序执行且不卡主线程 private let animationPrepareQueue = DispatchQueue(label: "com.yourApp.animationPrepareQueue", qos: .userInteractive) // 标记当前是否有动画在运行,防止重复触发 private var isAnimating = false override func viewDidLoad() { super.viewDidLoad() setupSpriteScene() // 启动动画序列 startAnimationSequence() } private func setupSpriteScene() { currentScene = SKScene(size: skView.bounds.size) currentScene.backgroundColor = .black skView.presentScene(currentScene) // 添加测试用动画节点 let testNode = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50)) testNode.name = "animationTarget" testNode.position = CGPoint(x: 50, y: currentScene.size.height/2) currentScene.addChild(testNode) } private func startAnimationSequence() { // ??? 启动第一个动画并衔接后续流程 // 👇 补全:先准备第一个动画,准备好就执行,执行完衔接下一个 prepareMoveAnimation { [weak self] moveAction in self?.executeAnimation(with: moveAction) { // 第一个动画运行时,后台开始准备第二个动画 self?.animationPrepareQueue.async { self?.prepareScaleAnimation { scaleAction in self?.executeAnimation(with: scaleAction) { // 第二个动画运行时,后台准备第三个动画 self?.animationPrepareQueue.async { self?.prepareFadeAnimation { fadeAction in self?.executeAnimation(with: fadeAction) { print("所有动画序列执行完成!") } } } } } } } } } // 准备第一个动画:移动节点 private func prepareMoveAnimation(completion: @escaping (SKAction) -> Void) { animationPrepareQueue.async { // 这里可做耗时准备:比如加载纹理、计算复杂路径 let moveAction = SKAction.moveTo(x: self.currentScene.size.width - 50, duration: 2) // 准备好后把动作传给执行方法 completion(moveAction) } } // ??? 执行动画并处理完成回调 // 👇 补全:SpriteKit操作必须在主线程,所以切回主队列 private func executeAnimation(with action: SKAction, completion: @escaping () -> Void) { DispatchQueue.main.async { [weak self] in guard let self = self, let targetNode = self.currentScene.childNode(withName: "animationTarget") else { return } self.isAnimating = true // 把动画动作和完成回调打包成序列 let completionAction = SKAction.run(completion) let animationSequence = SKAction.sequence([action, completionAction]) // 让节点运行这个序列 targetNode.run(animationSequence) { self.isAnimating = false } } } // 准备第二个动画:缩放节点 private func prepareScaleAnimation(completion: @escaping (SKAction) -> Void) { animationPrepareQueue.async { // 提前准备缩放动作(可在这里加载纹理帧等耗时操作) let scaleUp = SKAction.scale(to: 1.5, duration: 1) let scaleDown = SKAction.scale(to: 1.0, duration: 1) let scaleSequence = SKAction.sequence([scaleUp, scaleDown]) completion(scaleSequence) } } // 准备第三个动画:淡出并移除节点 private func prepareFadeAnimation(completion: @escaping (SKAction) -> Void) { animationPrepareQueue.async { let fadeOut = SKAction.fadeOut(withDuration: 1) let removeNode = SKAction.removeFromParent() let endSequence = SKAction.sequence([fadeOut, removeNode]) completion(endSequence) } } }
关键细节说明:
- 串行队列
animationPrepareQueue:用来处理所有动画的准备工作(比如加载纹理、计算路径),耗时操作在后台串行执行,既不阻塞主线程导致UI卡顿,又能保证准备顺序和动画执行顺序一致。 executeAnimation方法:SpriteKit的UI相关操作必须在主线程,所以这里强制切回主队列。同时我们把动画动作和完成回调打包成SKAction.sequence,确保动画完全结束后才触发下一个动画的执行。- 提前准备的实现:在前一个动画的
completion闭包里,立刻在后台队列启动下一个动画的准备——也就是说,前一个动画还在运行时,下一个动画的资源已经在后台准备好了,等前一个跑完就能立刻启动,完全符合你的需求。
优化建议(避免回调地狱):
如果动画序列很长,嵌套闭包会显得杂乱,可以把动画准备逻辑封装成数组,用递归遍历执行:
// 定义动画准备方法的数组 private let animationPreparers: [( @escaping (SKAction) -> Void ) -> Void] = [ prepareMoveAnimation, prepareScaleAnimation, prepareFadeAnimation ] // 递归执行动画序列 private func runNextAnimation(at index: Int = 0) { guard index < animationPreparers.count else { print("所有动画完成!") return } let currentPreparer = animationPreparers[index] currentPreparer { [weak self] action in self?.executeAnimation(with: action) { // 当前动画执行时,后台准备下一个 self?.animationPrepareQueue.async { self?.runNextAnimation(at: index + 1) } } } } // 启动时直接调用:runNextAnimation()
这样代码更整洁,扩展性也更强~
内容的提问来源于stack exchange,提问作者Optimalist
相关产品推荐
相关产品推荐

