ios - 在 SwiftUI 中重新关注第一响应者
问题描述
我知道如何UIViewRepresentable
在 SwiftUI 中创建一个以启用 TextField 的第一响应者功能:
struct FirstResponderTextField: UIViewRepresentable {
var placeholder: String
@Binding var text: String
func makeUIView(context: UIViewRepresentableContext<FirstResponderTextField>) -> UITextField {
let textField = UITextField()
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<FirstResponderTextField>) {
uiView.placeholder = placeholder
uiView.text = text
if (!uiView.isFirstResponder) {
uiView.becomeFirstResponder()
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var firstResponderTextField: FirstResponderTextField
init(_ firstResponderTextField: FirstResponderTextField) {
self.firstResponderTextField = firstResponderTextField
}
func textFieldDidChangeSelection(_ textField: UITextField) {
firstResponderTextField.text = textField.text ?? ""
}
}
}
我的问题是试图“重新聚焦”这个自定义文本字段。因此,虽然这个文本字段在我ContentView
的初始化时确实获得了焦点,但我想知道在它失去焦点之后如何以编程方式重新聚焦这个文本字段。
这是我的ContentView
:
struct ContentView: View {
@State var textField1: String = ""
@State var textField2: String = ""
var body: some View {
Form {
Section {
FirstResponderTextField(placeholder: "Text Field 1", text: $textField1)
TextField("Text Field 2", text: $textField2)
}
Section {
Button(action: {
// ???
}, label: {
Text("Re-Focus Text Field 1")
})
}
}
}
}
这是我尝试过的。我想也许我可以创建一个@State
可以控制的变量FirstResponderTextField
,所以我继续更改我的结构如下:
struct ContentView: View {
@State var textField1: String = ""
@State var textField2: String = ""
@State var isFocused: Bool = true
var body: some View {
Form {
Section {
FirstResponderTextField(placeholder: "Text Field 1", text: $textField1, isFocused: $isFocused)
TextField("Text Field 2", text: $textField2)
}
Section {
Button(action: {
self.isFocused = true
}, label: {
Text("Re-Focus Text Field 1")
})
}
}
}
}
struct FirstResponderTextField: UIViewRepresentable {
var placeholder: String
@Binding var text: String
@Binding var isFocused: Bool
func makeUIView(context: UIViewRepresentableContext<FirstResponderTextField>) -> UITextField {
let textField = UITextField()
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<FirstResponderTextField>) {
uiView.placeholder = placeholder
uiView.text = text
if (isFocused) {
uiView.becomeFirstResponder()
isFocused = false
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var firstResponderTextField: FirstResponderTextField
init(_ firstResponderTextField: FirstResponderTextField) {
self.firstResponderTextField = firstResponderTextField
}
func textFieldDidChangeSelection(_ textField: UITextField) {
firstResponderTextField.text = textField.text ?? ""
}
}
}
它似乎没有工作。我的意思是,当我第一次单击按钮时它起作用,但之后停止工作。
另外,我现在收到此警告:
在视图更新期间修改状态,这将导致未定义的行为。
是否可以创建一个UIViewRepresentable
可以随时重新聚焦的内容?
解决方案
您不应该在 FirstResponderTextField 中将 isFocused 设置为 false。
相反,在 FirstResponderTextField 中,观察 isFocused 绑定中的值变化,并相应地将您的控件设置为是否为第一响应者。
我在 github 上的这个 gist 中使用与 TextFieldState 对应的 ObserableObject 为您创建了一个解决方案
为了将来参考,这是我改变的:
- 而不是
@State var isFocused: Bool = true
在 ContentView 中,使用@ObservedObject var textFieldState = TextFieldState()
@ObservedObject var state: TextFieldState
在 FirstResponderTextField 中有一个属性- 只需在以下位置执行此操作
FirstResponderTextField.updateUIView
:
if state.isFirstResponder {
uiView.becomeFirstResponder()
}
推荐阅读
- python - 类型错误:dtype '
' 不明白 ; 在转换 DataFrame 的日期时? - c++ - 并行循环中的 CPU 使用率低
- javascript - Bootstrap 4.5 动画显示初始状态时打开页面时折叠
- reactjs - 我无法在 React 中对我的项目执行“npm install”。当我运行“npm install”时,我得到错误消息
- reactjs - 在 React 中更改路由更改的状态
- vue.js - 页面重新加载 Nuxt.js 时出现未定义数据错误
- pine-script - 在最后一个柱上查找系列值(Pine Script,Tradingview)
- xml - COBOL XML 生成:输入子变量值
- jquery - swal 火灾警报后无法在日期选择器模式中再次选择日期
- java - 大量的 wait_to_close 会话