我创建了一个UIViewRepresentable
来包裹UITextField
,以便:
enter
时,下一个文本字段可以设置为第一响应者在NavigationView
中使用时,除非从以前的视图中解雇了键盘,否则该视图不会观察其ObservedObject
中的值。
为什么会这样?我该怎么做才能解决此问题?
未从根视图中清除键盘:
从根视图的键盘已关闭:
这里是所说的UIViewRepresentable
struct SimplifiedFocusableTextField: UIViewRepresentable {
@Binding var text: String
private var isResponder: Binding<Bool>?
private var placeholder: String
private var tag: Int
public init(
_ placeholder: String = "",
text: Binding<String>,
isResponder: Binding<Bool>? = nil,
tag: Int = 0
) {
self._text = text
self.placeholder = placeholder
self.isResponder = isResponder
self.tag = tag
}
func makeUIView(context: UIViewRepresentableContext<SimplifiedFocusableTextField>) -> UITextField {
// create textfield
let textField = UITextField()
// set delegate
textField.delegate = context.coordinator
// configure textfield
textField.placeholder = placeholder
textField.setContentHuggingPriority(.defaultHigh, for: .vertical)
textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
textField.tag = self.tag
// return
return textField
}
func makeCoordinator() -> SimplifiedFocusableTextField.Coordinator {
return Coordinator(text: $text, isResponder: self.isResponder)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<SimplifiedFocusableTextField>) {
// update text
uiView.text = text
// set first responder ONCE
if self.isResponder?.wrappedValue == true && !uiView.isFirstResponder && !context.coordinator.didBecomeFirstResponder{
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
private var isResponder: Binding<Bool>?
var didBecomeFirstResponder = false
init(text: Binding<String>, isResponder: Binding<Bool>?) {
_text = text
self.isResponder = isResponder
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
func textFieldDidBeginEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.isResponder?.wrappedValue = true
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.isResponder?.wrappedValue = false
}
}
}
}
为了再现,这是contentView:
struct ContentView: View {
var body: some View {
return NavigationView { FieldView(tag: 0) }
}
}
这是包含字段及其视图模型的视图
struct FieldView: View {
@ObservedObject private var viewModel = FieldViewModel()
@State private var focus = false
var tag: Int
var body: some View {
return VStack {
// listen to viewModel's value
Text(viewModel.value)
// text field
SimplifiedFocusableTextField("placeholder", text: self.$viewModel.value, isResponder: $focus, tag: self.tag)
// push to stack
NavigationLink(destination: FieldView(tag: self.tag + 1)) {
Text("Continue")
}
// dummy for tapping to dismiss keyboard
Color.green
}
.onAppear {
self.focus = true
}.dismissKeyboardOnTap()
}
}
public extension View {
func dismissKeyboardOnTap() -> some View {
modifier(DismissKeyboardOnTap())
}
}
public struct DismissKeyboardOnTap: ViewModifier {
public func body(content: Content) -> some View {
return content.gesture(tapGesture)
}
private var tapGesture: some Gesture {
TapGesture().onEnded(endEditing)
}
private func endEditing() {
UIApplication.shared.connectedScenes
.filter {$0.activationState == .foregroundActive}
.map {$0 as? UIWindowScene}
.compactMap({$0})
.first?.windows
.filter {$0.isKeyWindow}
.first?.endEditing(true)
}
}
class FieldViewModel: ObservableObject {
var subscriptions = Set<AnyCancellable>()
// diplays
@Published var value = ""
}
答案 0 :(得分:0)
看起来又像SwiftUI渲染引擎过度优化 ...
这是固定的部分-只需使用heroku config set:DISABLE COLLECTSTATIC=0
强制使目的地唯一。经过Xcode 11.4 / iOS 13.4的测试
.id