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

如何在打开Context Menu时保持键盘显示且TextField处于聚焦状态?

如何在打开Context Menu时保持TextField聚焦且键盘不关闭?

打开Context Menu时,键盘会消失,处于激活状态的TextField会失去焦点。是否有办法保持键盘开启且TextField持续聚焦?以下示例代码可复现该问题:

struct ContentView: View {
    @State private var text: String = ""
    
    var body: some View {
        TextField(
            "Enter text",
            text: $text
        )
        .contextMenu {
            Button(action: {
                print("Hello")
            }) {
                Text("Hello")
            }
        }
    }
}

打开Context Menu前,键盘处于开启状态且TextField已聚焦:
打开Context Menu前的状态

打开Context Menu后,键盘关闭且TextField失去焦点:
打开Context Menu后的状态


解决方案

默认的SwiftUI contextMenu 会自动让TextField失去焦点,导致键盘收起。可以通过封装UIKit的UITextField并自定义上下文菜单交互,手动控制焦点状态来实现键盘保持开启的效果:

struct CustomTextField: UIViewRepresentable {
    @Binding var text: String
    @Binding var isFocused: Bool
    
    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.delegate = context.coordinator
        textField.placeholder = "Enter text"
        
        // 添加自定义上下文菜单交互
        let interaction = UIContextMenuInteraction(delegate: context.coordinator)
        textField.addInteraction(interaction)
        
        return textField
    }
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
        if isFocused {
            uiView.becomeFirstResponder()
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, UITextFieldDelegate, UIContextMenuInteractionDelegate {
        var parent: CustomTextField
        
        init(parent: CustomTextField) {
            self.parent = parent
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            parent.text = textField.text ?? ""
        }
        
        func textFieldDidBeginEditing(_ textField: UITextField) {
            parent.isFocused = true
        }
        
        // 构建自定义上下文菜单
        func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
            return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
                let helloAction = UIAction(title: "Hello") { _ in
                    print("Hello")
                    // 菜单关闭后重新聚焦
                    DispatchQueue.main.async {
                        self.parent.isFocused = true
                    }
                }
                return UIMenu(title: "", children: [helloAction])
            }
        }
        
        // 菜单展示完成后重新聚焦,防止键盘收起
        func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willDisplayMenuFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
            animator?.addCompletion {
                DispatchQueue.main.async {
                    self.parent.isFocused = true
                }
            }
        }
    }
}

// 使用示例
struct ContentView: View {
    @State private var text: String = ""
    @State private var isFocused: Bool = false
    
    var body: some View {
        CustomTextField(text: $text, isFocused: $isFocused)
            .frame(height: 44)
            .padding(.horizontal)
            .border(Color.gray)
    }
}

原理说明

通过UIViewRepresentable封装原生UITextField,利用UIContextMenuInteraction自定义上下文菜单,在菜单展示和关闭的回调中手动调用becomeFirstResponder()让TextField重新获取焦点,从而阻止键盘收起。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 07:15:33