Reputation: 771
I'm trying to make my textField (NSViewRepresentable
wrapped NSTextField
) the first responder when it appears. I have tested many answers in this thread, but they are either not working:
func updateNSView(_ nsView: MyField, context: Context) {
if some_condition {
print(nsViews.becomeFirstResponder()) // returns false
negate_condition()
}
...
}
Or it crashes with logs (=== AttributeGraph: cycle detected through attribute 43 ===)
:
func updateNSView(_ nsViews: MyField, context: Context) {
if some_condition {
Window.thisWindow?.makeFirstResponder(nsViews)
negate_condition()
}
...
}
What I am trying to achieve is:
@State var fieldActive: Bool
body: some View {
MyField(...).onAppear { /*makeFirstResponder if fieldActive == true*/ }
}
Can someone please help me on this? Thank you very much!
Upvotes: 3
Views: 1550
Reputation: 771
@Asperi provided a valid approach, I have found another path to the answer. I used the SwiftUI-Introspect library to complete the work with SwiftUI TextField (not wrapped NSTextField), here is the code:
struct SearchBar {
@Binding var shouldActivate: Bool
var body: some View {
TextField("", text: text)
.textFieldStyle(PlainTextFieldStyle())
.introspectTextField { textField in
if self.shouldActivate {
textField.becomeFirstResponder()
self.shouldActivate = false
}
textField.focusRingType = .none
}
}
Upvotes: 2
Reputation: 257653
If your MyField
is a NSTextField
the following works. Tested with Xcode 11.4 / macOS 10.15.4
func makeNSView(context: Context) -> MyField {
let view = MyField()
// ... other properties set up here
// wait for next cycle, so field be already in window
DispatchQueue.main.async {
view.window?.makeFirstResponder(view)
}
return view
}
Upvotes: 4