如何在快速点击时正确实现UIButton的按压/释放动画?
用UIViewPropertyAnimator就能完美解决这个问题,它支持对动画进度、状态做精细控制,刚好适配快速点击的场景,不会出现动画被突兀打断的情况。下面是具体实现步骤:
1. 定义动画控制器属性
在视图控制器里声明一个可选的UIViewPropertyAnimator属性,用来统一管理按钮的缩放动画:
var pressAnimator: UIViewPropertyAnimator?
2. 处理触摸按下事件(touchDown)
当用户按下按钮时,初始化或重置动画,让按钮平滑缩放到目标大小:
@objc func handleButtonPress(_ sender: UIButton) { // 如果已有未完成的动画,先停止并重置状态 pressAnimator?.stopAnimation(true) // 创建新的按压动画,时长0.1,缩放至0.5 pressAnimator = UIViewPropertyAnimator(duration: 0.1, curve: .easeInOut) { sender.transform = CGAffineTransform(scaleX: 0.5, y: 0.5) } pressAnimator?.startAnimation() }
3. 处理触摸抬起/取消事件(touchUpInside、touchCancel)
当用户松开按钮或滑动离开时,让动画反向播放,平滑恢复到原状态:
@objc func handleButtonRelease(_ sender: UIButton) { guard let animator = pressAnimator else { return } // 如果动画还在运行,直接反向播放;如果已完成,就执行恢复动画 if animator.isRunning { animator.isReversed = true } else { UIView.animate(withDuration: 0.1) { sender.transform = .identity } } // 动画结束后清理控制器,避免内存泄漏 animator.addCompletion { _ in sender.transform = .identity self.pressAnimator = nil } }
4. 给按钮绑定事件
在视图加载阶段,给按钮绑定对应的触摸事件:
override func viewDidLoad() { super.viewDidLoad() btnFoobar.addTarget(self, action: #selector(handleButtonPress(_:)), for: .touchDown) btnFoobar.addTarget(self, action: #selector(handleButtonRelease(_:)), for: [.touchUpInside, .touchCancel]) }
方案优势说明
之前用UIView.animate的问题在于,每次调用都会生成独立的动画实例,快速点击时新的恢复动画会直接打断未完成的按压动画,导致视觉跳变。而UIViewPropertyAnimator可以复用同一个动画实例,反向播放时会基于当前的动画进度平滑过渡,完全不会有突兀的打断感。同时还兼顾了用户滑动离开按钮的场景(touchCancel事件),确保按钮能正确恢复原状态。
内容的提问来源于stack exchange,提问作者jvic
相关产品推荐
相关产品推荐

