如何实现点击UIImageView后下落至y=0位置,现有while循环实现无效求解决方案
问题原因
- 你声明的
centerPosition是let修饰的常量,赋值后数值不会再改变,while循环的判断条件永远成立,会形成死循环直接阻塞主线程 - iOS的UI界面不会在你每次修改属性后立刻刷新,而是会等到当前RunLoop周期结束后批量更新,你在主线程中持续跑while循环时,系统永远没有机会执行界面渲染,看不到任何位置变化的过程
解决方案
最简便的实现方式是直接使用UIKit原生动画接口,系统会自动处理动画插值、界面渲染逻辑,性能更好,代码也更简洁:
@objc func handleTap(_ sender:UITapGestureRecognizer) { var targetFrame = bananaView.frame // 目标y轴位置为0 targetFrame.origin.y = 0 // withDuration参数是动画时长,单位为秒,可根据需要调整下落速度 UIView.animate(withDuration: 1.0) { bananaView.frame = targetFrame } }
如果需要模拟真实物理世界的下落加速、碰撞回弹效果,可以使用带弹性参数的动画接口:
@objc func handleTap(_ sender:UITapGestureRecognizer) { var targetFrame = bananaView.frame targetFrame.origin.y = 0 // usingSpringWithDamping取值0~1,数值越小回弹效果越明显;initialSpringVelocity是初始速度 UIView.animate(withDuration: 1.0, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.6) { bananaView.frame = targetFrame } }
如果你确实需要自行控制逐帧的位置更新,可使用和屏幕刷新率同步的CADisplayLink替代while循环,避免阻塞主线程:
var displayLink: CADisplayLink? var currentOriginY: CGFloat = 0 @objc func handleTap(_ sender:UITapGestureRecognizer) { // 记录视图当前初始y坐标 currentOriginY = bananaView.frame.origin.y // 启动同步屏幕刷新的定时器 displayLink = CADisplayLink(target: self, selector: #selector(updatePosition)) displayLink?.add(to: .main, forMode: .common) } @objc func updatePosition() { // 每次屏幕刷新调整y坐标,调整下方数值可修改下落速度 currentOriginY -= 3 var newFrame = bananaView.frame newFrame.origin.y = currentOriginY bananaView.frame = newFrame // 到达目标位置后停止定时器 if currentOriginY <= 0 { displayLink?.invalidate() displayLink = nil } }
内容的提问来源于stack exchange,提问作者Bon Doe
相关产品推荐
相关产品推荐

