You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在快速点击时正确实现UIButton的按压/释放动画?

解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 11:02:18