SwiftUI中TextEditor如何收起键盘 解决滚动时手势失效问题
SwiftUI TextEditor 键盘收起与手势冲突解决
问题原因
TextEditor 底层基于UIScrollView实现,内置滚动手势默认优先级高于外层绑定的自定义DragGesture,当内容超出容器高度触发内置滚动时,外层自定义手势会被系统拦截失效。同时早期SwiftUI版本没有直接暴露对应UIKit keyboardDismissMode 的修饰符,无法直接实现滚动收起键盘的效果。
实现方案
1. 滚动收起键盘实现(无手势冲突)
优先使用系统原生API实现,不需要自定义手势,完全兼容内置滚动逻辑:
- iOS 16及以上版本,直接使用系统提供的滚动键盘收起修饰符,支持交互式拖拽收起效果:
TextEditor(text: $newNote) // 可选值:.interactively 拖拽交互式收起、.immediately 滚动立刻收起、.never 滚动不收起 .scrollDismissesKeyboard(.interactively)
- 兼容iOS15及以下版本,可通过UIScrollView全局外观设置默认键盘收起模式,若需仅对当前页面生效,在页面退出时重置回默认值即可:
// 页面加载时调用,放在.onAppear或App启动入口中 UIScrollView.appearance().keyboardDismissMode = .onDrag // 页面退出时调用,放在.onDisappear中,避免影响其他页面滚动逻辑 UIScrollView.appearance().keyboardDismissMode = .default
2. 自定义手势与内置滚动冲突修复
原有代码中使用.gesture绑定的手势优先级低于TextEditor内置滚动手势,会被滚动事件拦截,替换为.simultaneousGesture即可让自定义手势与内置滚动手势同时识别,不会出现滚动时手势失效的问题。
修改后的完整代码参考:
VStack{ TextEditor(text: $newNote) .scrollDismissesKeyboard(.interactively) } .simultaneousGesture( DragGesture(minimumDistance: 20, coordinateSpace: .global) .onEnded({ value in // 右滑返回逻辑 if value.translation.width > 0 { self.presentationMode.wrappedValue.dismiss() hideKeyboard() self.navigationBarBackButtonHidden = false } // 下滑收键盘逻辑已由.scrollDismissesKeyboard原生实现,无需重复处理 }) ) // 原有收起键盘扩展可正常复用 extension View { func hideKeyboard() { let resign = #selector(UIResponder.resignFirstResponder) UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil) } }
注意事项
- 若使用全局UIScrollView.appearance设置,务必在不需要该逻辑的页面重置属性,避免影响其他列表、滚动视图的交互
- 如果自定义手势需要完全抢占交互优先级,可将
.simultaneousGesture替换为.highPriorityGesture,但该方式会打断TextEditor的原生滚动逻辑,按需选择即可
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

