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
相关产品推荐
相关产品推荐

