UIView.animate使用难题:长按按钮触发屏幕填充动画功能实现遇阻
解决UIView.animate实现长按填充屏幕的问题
嘿,我明白你要实现的这个长按填充效果——看起来简单但细节容易踩坑,我帮你梳理下完整的实现方案,包括你提到的到顶后的状态切换,还有松开按钮的中断逻辑(按常见需求补上啦)。
核心实现思路
我们需要分三个核心环节处理:
- 识别长按手势的开始/结束事件
- 控制
bar视图的向上动画,以及动画完成后的状态切换 - 处理用户中途松开按钮时的动画中断与重置
完整代码示例(Swift)
首先准备好基础UI元素,然后绑定手势并实现逻辑:
import UIKit class ViewController: UIViewController { // 底部填充的bar视图 private let fillBar = UIView() // 触发长按的按钮 private let triggerButton = UIButton(type: .system) // 记录当前是否在动画中,避免重复触发 private var isAnimating = false // 记录bar当前的颜色,方便切换 private var currentBarColor: UIColor = .systemBlue override func viewDidLoad() { super.viewDidLoad() setupUI() setupLongPressGesture() } private func setupUI() { // 设置背景视图 view.backgroundColor = .systemBackground // 配置填充bar fillBar.backgroundColor = currentBarColor fillBar.translatesAutoresizingMaskIntoConstraints = false view.addSubview(fillBar) // 配置触发按钮 triggerButton.setTitle("长按填充", for: .normal) triggerButton.titleLabel?.font = .systemFont(ofSize: 18, weight: .medium) triggerButton.translatesAutoresizingMaskIntoConstraints = false view.addSubview(triggerButton) // 布局约束:bar初始在底部,高度为0(隐藏状态),宽度和屏幕一致 NSLayoutConstraint.activate([ fillBar.bottomAnchor.constraint(equalTo: view.bottomAnchor), fillBar.leadingAnchor.constraint(equalTo: view.leadingAnchor), fillBar.trailingAnchor.constraint(equalTo: view.trailingAnchor), fillBar.heightAnchor.constraint(equalToConstant: 0), triggerButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), triggerButton.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } private func setupLongPressGesture() { let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:))) // 设置长按触发的最小时长,比如0.2秒,让用户快速长按就能触发 longPress.minimumPressDuration = 0.2 triggerButton.addGestureRecognizer(longPress) } @objc private func handleLongPress(_ gesture: UILongPressGestureRecognizer) { switch gesture.state { case .began: startFillAnimation() case .ended, .cancelled, .failed: cancelFillAnimation() default: break } } private func startFillAnimation() { guard !isAnimating else { return } isAnimating = true // 取消初始高度约束,设置top锚点到屏幕底部 fillBar.heightAnchor.constraint(equalToConstant: 0).isActive = false let topConstraint = fillBar.topAnchor.constraint(equalTo: view.bottomAnchor) topConstraint.isActive = true view.layoutIfNeeded() // 执行向上填充动画,时长可按需调整 UIView.animate(withDuration: 2.0, animations: { topConstraint.constant = 0 // bar的top移到屏幕顶部,填满整个屏幕 self.view.layoutIfNeeded() }, completion: { [weak self] finished in guard let self = self, finished else { return } // 动画完成:修改背景色、隐藏bar并切换颜色 self.view.backgroundColor = self.currentBarColor // 重置bar的约束为隐藏状态 topConstraint.isActive = false self.fillBar.heightAnchor.constraint(equalToConstant: 0).isActive = true self.view.layoutIfNeeded() // 切换bar的颜色,可自定义颜色逻辑 self.currentBarColor = self.currentBarColor == .systemBlue ? .systemGreen : .systemBlue self.fillBar.backgroundColor = self.currentBarColor self.isAnimating = false }) } private func cancelFillAnimation() { guard isAnimating else { return } isAnimating = false // 停止当前动画,重置bar到初始隐藏状态 fillBar.layer.removeAllAnimations() fillBar.topAnchor.constraint(equalTo: view.bottomAnchor).isActive = false fillBar.heightAnchor.constraint(equalToConstant: 0).isActive = true view.layoutIfNeeded() } }
关键细节说明
- 状态控制:用
isAnimating变量避免重复触发动画,防止手势多次触发导致的动画混乱 - 动画完成回调:必须判断
finished参数,确保是动画正常完成才执行后续的背景色切换和bar状态修改,而不是中途被打断 - 手势状态处理:覆盖
.ended、.cancelled、.failed三种状态,确保任何情况松开按钮都能中断动画 - 约束重置:动画结束或中断后,正确重置约束避免布局冲突
内容的提问来源于stack exchange,提问作者Bela
相关产品推荐
相关产品推荐

