SwiftUI中点击NavigationLink时收起键盘并提交TextField内容
方案一:替换NavigationLink为Button,手动控制导航
直接在点击事件中先处理收起键盘、提交文本的逻辑,再手动触发导航,避免手势冲突。
假设你使用的是NavigationStack,代码示例如下:
import SwiftUI struct YourView: View { @State private var path = NavigationPath() @FocusState private var isFocusedField1: Bool @State private var text1 = "" let items: [Item] // 你的自定义Item数组 // 提交文本的逻辑方法 private func submitText() { // 在这里实现文本提交逻辑,比如保存到数据源、发送请求等 print("已提交文本:\(text1)") } var body: some View { NavigationStack(path: $path) { List { Section("Input") { HStack { Text("Field 1") Spacer() TextField("Text 1", text: $text1) .focused($isFocusedField1) } } Section("Items") { ForEach(items) { item in Button { // 1. 取消TextField焦点,收起键盘 isFocusedField1 = false // 2. 提交文本 submitText() // 3. 手动导航到目标页面 path.append(item) } label: { ItemView(item: item) } } } } .navigationDestination(for: Item.self) { item in // 替换为你的目标详情视图 DetailView(item: item) } } } } // 示例:自定义Item和详情视图 struct Item: Identifiable { let id = UUID() let name: String } struct ItemView: View { let item: Item var body: some View { Text(item.name) } } struct DetailView: View { let item: Item var body: some View { Text("详情:\(item.name)") .navigationTitle(item.name) } }
方案二:使用UIKit全局手势监听点击
通过给应用窗口添加手势识别器,点击非TextField区域时自动收起键盘并提交文本,无需修改原有NavigationLink结构。
首先创建自定义ViewModifier:
import SwiftUI struct DismissKeyboardOnTapModifier: ViewModifier { @Binding var isFocused: Bool @Binding var text: String private var tapGesture: UITapGestureRecognizer? func body(content: Content) -> some View { content .onAppear { tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) tapGesture?.cancelsTouchesInView = false // 关键:不拦截其他视图的手势响应 UIApplication.shared.windows.first?.addGestureRecognizer(tapGesture!) } .onDisappear { // 页面消失时移除手势,避免内存泄漏 if let gesture = tapGesture { UIApplication.shared.windows.first?.removeGestureRecognizer(gesture) } } } @objc private func handleTap(_ gesture: UITapGestureRecognizer) { let location = gesture.location(in: nil) // 判断点击位置是否在TextField之外 if let tappedView = UIApplication.shared.windows.first?.hitTest(location, with: nil), !(tappedView is UITextField) { isFocused = false submitText() } } private func submitText() { print("已提交文本:\(text)") // 在这里实现文本提交逻辑 } } // 给View添加扩展,方便调用 extension View { func dismissKeyboardOnTap(isFocused: Binding<Bool>, text: Binding<String>) -> some View { self.modifier(DismissKeyboardOnTapModifier(isFocused: isFocused, text: text)) } }
然后在你的视图中使用该Modifier:
struct YourView: View { @FocusState private var isFocusedField1: Bool @State private var text1 = "" let items: [Item] var body: some View { NavigationStack { List { Section("Input") { HStack { Text("Field 1") Spacer() TextField("Text 1", text: $text1) .focused($isFocusedField1) } } Section("Items") { ForEach(items) { item in NavigationLink(value: item) { ItemView(item: item) } } } } .dismissKeyboardOnTap(isFocused: $isFocusedField1, text: $text1) .navigationDestination(for: Item.self) { item in DetailView(item: item) } } } }
方案对比
- 方案一:纯SwiftUI原生实现,逻辑清晰,无UIKit依赖,适合大多数场景。
- 方案二:保留原有NavigationLink结构,但依赖UIKit,需要注意手势的生命周期管理,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Roman
相关产品推荐
相关产品推荐

