Swift中animateKeyframes的withRelativeStartTime不生效问题
问题根源
你这问题的核心是:UIView关键帧动画的animations闭包里所有代码,会在动画启动时一次性执行完,根本不会按你设置的relativeStartTime延迟触发。你在第二个关键帧里写的startAnimating(),会和第一个移动动画的代码同时跑,自然就出现了两者同步启动的情况——从日志里两个操作的时间戳完全一致,也能佐证这一点。
修复方案
给你两种靠谱的实现顺序动画的方式:
方案一:用动画的completion回调拆分阶段
把移动动画和GIF启动拆成两个独立步骤,利用第一个动画的完成回调触发第二个操作,逻辑最清晰:
func startMoving() { let moveDuration: Double = 0.7 // 第一步:执行frontImageView的移动动画 UIView.animate(withDuration: moveDuration, animations: { print(">>> start transfrom", Date()) self.frontImageView.transform = CGAffineTransform(translationX: -20, y: 0) }, completion: { _ in // 移动完成后再启动GIF动画 print(">>> start animating", Date()) self.backgroundImageView.startAnimating() // 按原需求总时长4秒后停止GIF let remainingTime = 4 - moveDuration DispatchQueue.main.asyncAfter(deadline: .now() + remainingTime) { self.backgroundImageView.stopAnimating() } }) }
方案二:用延迟任务启动GIF
如果想保留关键帧动画的结构,也可以在移动动画开始后,延迟对应时长再启动GIF:
func startMoving() { let totalDuration: Double = 4 let moveDuration: Double = 0.7 // 执行移动的关键帧动画 UIView.animateKeyframes(withDuration: totalDuration, delay: 0, options: [.calculationModeLinear], animations: { UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: moveDuration/totalDuration, animations: { print(">>> start transfrom", Date()) self.frontImageView.transform = CGAffineTransform(translationX: -20, y: 0) }) }, completion: { _ in self.backgroundImageView.stopAnimating() }) // 延迟moveDuration秒后启动GIF DispatchQueue.main.asyncAfter(deadline: .now() + moveDuration) { print(">>> start animating", Date()) self.backgroundImageView.startAnimating() } }
补充说明
UIView动画的animations闭包是用来定义动画的最终状态的,闭包里的属性修改会被系统转换成动画过程,但像调用方法、打印日志这类非属性修改的代码,都会在动画启动前同步执行,不会被设置的时间参数延迟。
内容的提问来源于stack exchange,提问作者malcopolocei
相关产品推荐
相关产品推荐

