如何提前停止sceneView.pointOfView的SCNTransaction动画?
解决SceneKit视角动画无法手动停止的问题
问题原因
你当前的实现逻辑存在本质问题:SCNAction.run 只是一次性执行闭包内的代码,执行完毕后这个Action就已经结束了。真正驱动视角变化的是 SCNTransaction 底层的Core Animation动画,它和SceneKit的Action系统完全独立,所以调用 removeAllActions() 根本无法触及这个Core Animation动画,自然起不到停止效果。
解决方案
这里提供两种可行的解决思路,根据你的需求选择:
方案一:改用SceneKit Action实现动画(推荐)
直接用SceneKit原生的SCNAction来实现视角的位移动画,这样整个动画由SceneKit的Action系统管理,调用removeAllActions()就能正常停止动画。
示例代码:
// 假设你要设置的目标位置是targetPosition,目标朝向是targetOrientation // 组合位移动画和朝向动画(按需选择) let moveAction = SCNAction.move(to: targetPosition, duration: duration) let rotateAction = SCNAction.rotate(toAxisAngle: targetOrientation, duration: duration) let groupAction = SCNAction.group([moveAction, rotateAction]) // 设置动画曲线 groupAction.timingFunction = CAMediaTimingFunction(name: easing) // 设置完成回调 groupAction.completionBlock = { finished in if finished { completion?() } } // 执行动画 sceneView.pointOfView?.runAction(groupAction) // 停止动画时直接调用 sceneView.pointOfView?.removeAllActions()
方案二:手动终止Core Animation动画(保留SCNTransaction的情况下)
如果必须使用SCNTransaction,需要直接操作Core Animation层面来停止动画,同时要手动将视角属性同步到动画的当前帧,避免跳变。
示例代码:
// 停止动画的方法 func stopPOVAnimation() { guard let pov = sceneView.pointOfView else { return } // 将视角属性同步到动画的实时状态,防止停止后跳回初始值 if let presentationPov = pov.presentation { pov.position = presentationPov.position pov.orientation = presentationPov.orientation } // 移除所有Core Animation动画 pov.removeAllAnimations() // 若上面无效,直接操作layer pov.layer?.removeAllAnimations() // 手动触发完成回调(按需调用) completion?() }
内容的提问来源于stack exchange,提问作者Hassan Taleb
相关产品推荐
相关产品推荐

