如何在打开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后,键盘关闭且TextField失去焦点:
解决方案
默认的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
相关产品推荐
相关产品推荐

