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

UIScrollView如何实现类似WhatsApp拖动未触键盘就启动交互式收起

预期实现效果(与WhatsApp一致)

WhatsApp交互演示动图
从动图中可以看到,WhatsApp的键盘收起操作在拖动触碰到底部栏边缘时就会触发,无需接触到键盘边缘。请问需要使用什么技术方案才能实现该行为?

补充说明

我们的底部工具栏会跟随键盘移动,因为底部工具栏的底部与安全区(Safe Area)底部之间设置了约束。我们通过在全局Window上添加手势识别器来调整底部约束的constant值,相关实现代码片段如下:

@objc private func didPan(_ sender: UIPanGestureRecognizer){
    if keyboardHeight > 0 {
        let mainScrollView = editable.mainScrollView
        
        let isScrolling = (mainScrollView.isDragging || mainScrollView.isDecelerating)

        if isScrolling {
            if let mainScrollViewGlobalOrigin = mainScrollView.globalOrigin {
                let point = sender.location(in: sender.view!)
                
                // Take safe area into consideration, like iPhone 12 Pro Max.
                let key = UIWindow.key
                let bottomSafeArea = key?.safeAreaInsets.bottom ?? 0
                
                let dy = point.y - (
                    mainScrollViewGlobalOrigin.y +
                    mainScrollView.frame.height +
                    toolbarHeightLayoutConstraint.constant +
                    bottomSafeArea -
                    bottomLayoutConstraint.constant -
                    self.keyboardHeight
                )
                
                if dy > 0 {
                    bottomLayoutConstraint.constant = -(keyboardHeight - dy)
                }
            }
        }
    }
}

解决方案

你可以在现有手势逻辑的基础上做如下改造,即可实现预期交互效果:

  1. 允许多手势同时识别
    实现UIGestureRecognizerDelegate代理方法,允许你添加的全局pan手势和UIScrollView自带的滚动手势同时响应:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}
  1. 改造手势处理逻辑,手动同步键盘位移
    在原有didPan方法基础上新增键盘位置控制逻辑,不需要依赖系统默认的键盘交互触发规则:
// 新增变量存储手势开始时的键盘初始Y坐标
private var initialKeyboardY: CGFloat = 0

@objc private func didPan(_ sender: UIPanGestureRecognizer){
    guard keyboardHeight > 0, let mainScrollView = editable.mainScrollView else { return }
    let isScrolling = (mainScrollView.isDragging || mainScrollView.isDecelerating)
    guard isScrolling else { return }
    
    // 获取键盘所在的独立Window
    guard let keyboardWindow = UIApplication.shared.windows.first(where: { $0.windowLevel == .keyboard }) else { return }
    
    switch sender.state {
    case .began:
        // 手势启动时记录键盘初始位置
        initialKeyboardY = keyboardWindow.frame.minY
    case .changed:
        guard let mainScrollViewGlobalOrigin = mainScrollView.globalOrigin, let keyWindow = UIWindow.key else { return }
        let point = sender.location(in: sender.view!)
        let bottomSafeArea = keyWindow.safeAreaInsets.bottom ?? 0
        
        // 自定义触发阈值:底部工具栏的上边缘Y坐标
        let triggerThresholdY = mainScrollViewGlobalOrigin.y + mainScrollView.frame.height
        
        let dy = point.y - triggerThresholdY
        guard dy > 0 else { return }
        
        // 同步更新底部工具栏约束和键盘位置
        bottomLayoutConstraint.constant = -(keyboardHeight - dy)
        keyboardWindow.frame.origin.y = initialKeyboardY + dy
    case .ended, .cancelled:
        let velocity = sender.velocity(in: sender.view).y
        let currentKeyboardOffset = keyboardWindow.frame.minY - initialKeyboardY
        // 判断收起逻辑:拖动超过键盘一半高度 或 向下滑动速度足够大就收起,否则回弹
        let shouldDismiss = currentKeyboardOffset > keyboardHeight / 2 || velocity > 300
        
        UIView.animate(withDuration: 0.25) {
            if shouldDismiss {
                self.bottomLayoutConstraint.constant = 0
                keyboardWindow.frame.origin.y = UIScreen.main.bounds.height
                self.view.endEditing(true)
            } else {
                self.bottomLayoutConstraint.constant = -self.keyboardHeight
                keyboardWindow.frame.origin.y = self.initialKeyboardY
            }
            self.view.layoutIfNeeded()
        }
    default:
        break
    }
}
  1. 可选兼容方案
    如果你不想直接操作系统键盘Window,也可以监听UIResponder.keyboardWillChangeFrameNotification通知,在系统回调中同步更新底部工具栏约束,效果完全一致。

内容的提问来源于stack exchange,提问作者Cheok Yan Cheng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 02:54:05