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

如何在手指触达前收起iOS键盘

实现UIScrollView键盘提前40像素交互式收起

我之前也碰到过类似的需求,默认的interactive键盘收起必须要手指碰到键盘才会触发,要让它提前40像素就响应,我们可以通过监听键盘状态、拦截拖拽手势,再手动控制键盘收起的交互过程来实现,具体步骤如下:

1. 监听键盘高度,记录关键位置

首先我们需要获取键盘的实时高度,这样才能计算出“提前40像素”的触发区域:

class YourViewController: UIViewController {
    @IBOutlet weak var scrollView: UIScrollView!
    private var keyboardHeight: CGFloat = 0
    private let triggerOffset: CGFloat = 40 // 提前触发的距离
    
    override func viewDidLoad() {
        super.viewDidLoad()
        scrollView.keyboardDismissMode = .interactive
        
        // 注册键盘通知,获取键盘高度
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    @objc private func keyboardWillShow(_ notification: Notification) {
        guard let userInfo = notification.userInfo,
              let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
        // 转换为当前视图坐标系下的键盘高度
        keyboardHeight = view.convert(keyboardFrame, from: nil).height
    }
    
    @objc private func keyboardWillHide(_ notification: Notification) {
        keyboardHeight = 0
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

2. 自定义ScrollView拦截拖拽手势

我们需要自定义UIScrollView子类,拦截它的拖拽手势,判断手指位置是否进入提前触发区域,一旦进入就手动启动键盘的交互式收起:

class PreDismissScrollView: UIScrollView {
    var keyboardHeight: CGFloat = 0
    let triggerOffset: CGFloat = 40
    private var isTriggeringDismiss = false
    
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        // 仅处理拖拽手势,且键盘处于显示状态
        guard let panGesture = gestureRecognizer as? UIPanGestureRecognizer, keyboardHeight > 0 else {
            return super.gestureRecognizerShouldBegin(gestureRecognizer)
        }
        
        let touchLocation = panGesture.location(in: self)
        // 计算当前视图中键盘顶部的Y坐标
        let keyboardTopY = bounds.height - keyboardHeight
        // 判断手指是否处于键盘上方40像素范围内
        let isInTriggerZone = touchLocation.y >= (keyboardTopY - triggerOffset) && touchLocation.y <= keyboardTopY
        
        if isInTriggerZone {
            isTriggeringDismiss = true
            // 让第一响应者 resign,启动键盘收起的交互流程
            UIResponder.currentFirstResponder()?.resignFirstResponder()
            // 同步scrollView的拖拽偏移,让视觉上更连贯
            let translation = panGesture.translation(in: self)
            contentOffset.y += translation.y
            panGesture.setTranslation(.zero, in: self)
        }
        
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }
    
    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if isTriggeringDismiss {
            // 当拖拽过程中,根据scrollView的偏移量调整键盘收起的进度
            let dismissProgress = (contentOffset.y - (contentSize.height - bounds.height + keyboardHeight - triggerOffset)) / triggerOffset
            // 这里可以配合UIPercentDrivenInteractiveTransition来更精准控制动画
            // 如果不需要精细控制,系统默认的interactive dismiss会自动跟进
        }
    }
}

// 扩展UIResponder,方便获取当前第一响应者
extension UIResponder {
    static func currentFirstResponder() -> UIResponder? {
        _currentFirstResponder = nil
        UIApplication.shared.sendAction(#selector(findFirstResponder(_:)), to: nil, from: nil, for: nil)
        return _currentFirstResponder
    }
    
    private static weak var _currentFirstResponder: UIResponder?
    
    @objc private func findFirstResponder(_ sender: Any) {
        UIResponder._currentFirstResponder = self
    }
}

3. 适配ViewController中的ScrollView

把你原有的UIScrollView替换成自定义的PreDismissScrollView,并在ViewController中传递键盘高度:

// 在keyboardWillShow方法中添加
if let customScrollView = scrollView as? PreDismissScrollView {
    customScrollView.keyboardHeight = keyboardHeight
}

关键说明

  • 我们通过判断手指在scrollView中的位置,提前触发resignFirstResponder(),启动键盘的交互式收起流程;
  • 同步scrollView的拖拽偏移是为了让手指移动和键盘收起的视觉效果更连贯,避免突兀;
  • 如果需要更精细的动画控制,可以结合UIPercentDrivenInteractiveTransition类,手动控制键盘收起的进度百分比。

内容的提问来源于stack exchange,提问作者Laurent Crivello

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:42:13