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

SwiftUI中如何避免ScrollView滚动时带动键盘滚动?

解决SwiftUI中ScrollView滚动时键盘跟随滚动的问题

在SwiftUI的聊天类界面场景中,使用ScrollView搭配TextField组件时,为了实现滚动时隐藏弹出的键盘,我们会用到scrollDismissesKeyboard属性,但设置为.interactively模式时会出现问题:滚动ScrollView后滑动到键盘区域,键盘会跟随滚动。

以下是几种可行的解决方法:

方案一:修改键盘关闭模式

将scrollDismissesKeyboard的模式从.interactively改为.onDrag,该模式下只有拖拽ScrollView的内容区域时才会触发键盘收起,滑动到键盘区域时不会产生跟随滚动的行为,实现起来最简单:

ScrollView {
    TextBox(text: "Test 1", color: .red)
    TextBox(text: "Test 2", color: .green)
    TextBox(text: "Test 3", color: .blue)
    TextBox(text: "Test 4", color: .red)
    TextBox(text: "Test 5", color: .green)
    TextBox(text: "Test 6", color: .blue)
}
.scrollDismissesKeyboard(.onDrag)

方案二:主动触发键盘收起

如果需要保留部分交互式关闭的特性,也可以禁用默认的交互式关闭,通过监听ScrollView的拖拽手势主动收起键盘:

ScrollView {
    TextBox(text: "Test 1", color: .red)
    TextBox(text: "Test 2", color: .green)
    TextBox(text: "Test 3", color: .blue)
    TextBox(text: "Test 4", color: .red)
    TextBox(text: "Test 5", color: .green)
    TextBox(text: "Test 6", color: .blue)
}
.scrollDismissesKeyboard(.never)
.gesture(
    DragGesture()
        .onChanged { _ in
            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        }
)

方案三:调整ScrollView内容内边距

通过监听键盘的弹出/收起通知,动态给ScrollView添加底部内边距,确保滚动区域不会延伸到键盘下方,从根源上避免滑动到键盘区域的情况,同时保留交互式关闭的体验:

import SwiftUI

struct TestKeyboard: View {
    @State var text: String = ""
    @State private var keyboardHeight: CGFloat = 0
    
    var body: some View {
        VStack {
            ScrollView {
                TextBox(text: "Test 1", color: .red)
                TextBox(text: "Test 2", color: .green)
                TextBox(text: "Test 3", color: .blue)
                TextBox(text: "Test 4", color: .red)
                TextBox(text: "Test 5", color: .green)
                TextBox(text: "Test 6", color: .blue)
            }
            .scrollDismissesKeyboard(.interactively)
            .padding(.bottom, keyboardHeight)
            
            TextField(text: $text) {
                Text("Test Field")
            }
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
            guard let frame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
            keyboardHeight = frame.height
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
            keyboardHeight = 0
        }
    }
}

struct TestKeyboard_Previews: PreviewProvider {
    static var previews: some View {
        TestKeyboard()
    }
}

方案特点说明

  • 方案一:代码改动最小,适合不需要复杂交互的场景;
  • 方案二:自定义性强,可根据需求调整键盘收起的触发时机;
  • 方案三:从布局层面解决问题,同时保留原生的交互式键盘关闭体验,适合聊天类等对布局精度要求高的场景。

内容的提问来源于stack exchange,提问作者Ivan Pomortsev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 22:00:34