2

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!

BoltClock
  • 665,005
  • 155
  • 1,345
  • 1,328
WatashiJ
  • 674
  • 5
  • 16

2 Answers2

3

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
  }
Asperi
  • 173,274
  • 14
  • 284
  • 455
  • This approach is a working approach. So I will pick yours as the valid answer. I found a different approach, and I will post it down below. Thank you for answering – WatashiJ Apr 19 '20 at 14:44
2

@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
      }
}
WatashiJ
  • 674
  • 5
  • 16