Swift 4中UIView.animate与CGRect联动异常:连续点击跳跃高度不符
解决连续点击按钮后角色上移高度异常的问题
嘿,这个问题我之前做类似的动画交互时也踩过坑!咱们先拆解下为什么会出现这种情况:
你当前的代码存在两个核心问题:
- 多组动画并行叠加冲突:你连续调用了两个
UIView.animate方法,这两个动画其实是同时启动执行的(因为UIKit动画是异步的),只是第一个动画时长更短,视觉上像是先上移再下落,但本质上两个动画在同时修改角色的frame属性。当你连续点击按钮时,会触发多组这样的并行动画,它们的目标值互相干扰,直接导致角色的位移偏离预期。 - 起点值获取不准确:每次点击时你都用
self.TheCharacter.frame.origin.y作为位移起点,但如果此时有动画正在执行,这个frame值其实是动画最终要到达的目标值,而不是当前屏幕上角色的实际显示位置,这就导致计算出来的上移/下落起点完全错误。
修正后的代码方案
import UIKit class ViewController: UIViewController { @IBOutlet weak var TheCharacter: UIImageView! @IBOutlet weak var TheRocket: UIImageView! @IBAction func TheCharacterJumps(_ sender: Any) { // 1. 终止当前所有正在运行的动画,避免新旧动画叠加冲突 TheCharacter.layer.removeAllAnimations() // 2. 获取角色当前在屏幕上的真实显示位置 // 动画执行时,presentationLayer保存的是当前视觉上的帧,而不是最终目标帧 let currentDisplayFrame = TheCharacter.layer.presentation()?.frame ?? TheCharacter.frame let currentY = currentDisplayFrame.origin.y // 3. 链式执行动画:上移动画完成后再启动下落动画 UIView.animate(withDuration: 0.35, animations: { self.TheCharacter.frame = CGRect(x: 167, y: currentY - 200, width: 40, height: 40) }) { [weak self] finished in guard let self = self else { return } // 上移动画结束后,执行下落动画 UIView.animate(withDuration: 2, animations: { self.TheCharacter.frame = CGRect(x: 167, y: currentY + 435, width: 40, height: 40) }) } } }
关键改动说明
- 终止当前动画:通过
TheCharacter.layer.removeAllAnimations()确保每次点击按钮时,之前未完成的动画都会被终止,从根源避免多组动画的冲突。 - 获取真实显示位置:利用
presentationLayer获取角色当前在屏幕上的实际位置,而不是直接使用可能已经是动画目标值的frame,保证每次位移计算的起点都是准确的。 - 链式执行动画:把下落动画放在上移动画的
completion闭包里,确保严格按照“先上移→再下落”的顺序执行,彻底解决并行动画的目标值干扰问题。
这样修改后,不管你连续点击多少次按钮,角色都会基于当前的实际位置先准确上移200y,然后再开始下落,不会出现位移异常的情况啦~
内容的提问来源于stack exchange,提问作者user9313040
相关产品推荐
相关产品推荐

