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

SwiftUI中点击NavigationLink时收起键盘并提交TextField内容

解决SwiftUI中点击NavigationLink时收起键盘并提交文本的问题

方案一:替换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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 10:29:53