Swift中如何为UIView.animate自动反转添加前置延迟?
UIKit动画:在自动反转前添加延迟的Swift实现方案
一、自动反转前添加延迟的标准实现方式
UIKit的UIView.animate自带的.autoreverse选项没有直接设置反转前延迟的参数,因此放弃.autoreverse+.repeat组合,改用completion闭包递归调用动画是常规的可靠方案,你自己找到的代码就是可行的:
func animateCloud() { // 每次动画开始前重置到起始位置 cloudImage.frame = CGRect(x: 200, y: 0, width: 80, height: 80) UIView.animate(withDuration: 4.0, delay: 2.0, options: [.curveLinear], animations: { self.cloudImage.frame = CGRect(x: -80, y: 0, width: 80, height: 80) }, completion: { _ in // 动画完成后递归调用,实现循环 self.animateCloud() }) }
另外你考虑过的关键帧动画也是可行方案,通过添加"停留帧"来实现延迟,代码示例如下:
UIView.animateKeyframes(withDuration: 10.0, delay: 0, options: [.repeat], animations: { // 第一帧:从X=200移动到X=-80,耗时4秒 UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.4) { cloudImage.frame = CGRect(x: -80, y: 0, width: 80, height: 80) } // 第二帧:停留2秒(占总时长的20%) UIView.addKeyframe(withRelativeStartTime: 0.4, relativeDuration: 0.2) { // 位置不变,实现延迟效果 cloudImage.frame = CGRect(x: -80, y: 0, width: 80, height: 80) } // 第三帧:从X=-80移动回X=200,耗时4秒 UIView.addKeyframe(withRelativeStartTime: 0.6, relativeDuration: 0.4) { cloudImage.frame = CGRect(x: 200, y: 0, width: 80, height: 80) } }, completion: nil)
总时长10秒(4+2+4),通过相对时间分配控制各阶段时长,适合更复杂的多阶段动画组合。
二、关于UIImageView用let还是var的疑问
UI动画并没有直接修改UIImageView内部frame结构体的原始值——UIKit动画作用在视图的**呈现层(presentation layer)**上,动画过程中看到的视图位置是呈现层的临时状态,动画结束后若未设置.fillMode,视图会自动回到原始frame。
UIImageView是引用类型,let声明表示变量的引用不能被修改(不能把它重新赋值为另一个UIImageView实例),但完全可以修改它的属性(比如frame、image等),所以Xcode建议用let是合理的,因为你不需要重新赋值这个UIImageView实例。
三、关于_ in的含义
在Swift闭包中,_是用来忽略参数的语法。这里completion闭包的默认参数是一个Bool值(表示动画是否正常完成,还是被打断),_ in就是告诉编译器:我们不需要使用这个参数,直接执行闭包内的递归逻辑即可。如果需要用到这个参数,你可以写成:
completion: { finished in if finished { self.animateCloud() } }
这样就能判断动画是否完成后再决定是否循环。
内容的提问来源于stack exchange,提问作者chrisallick
相关产品推荐
相关产品推荐

