Issue #589
Use onTapGesture 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 import SwiftUIstruct MyTextField : View { @Binding var text: String let placeholder: String @State private var isFocus: Bool = false var body: some View { FocusTextField (text: $text, placeholder: placeholder, isFocus: $isFocus) .padding() .cornerRadius(4 ) .overlay( RoundedRectangle (cornerRadius: 4 ) .stroke(isFocus ? Color .accentColor: Color .separator) ) .onTapGesture { isFocus = true } } } private struct FocusTextField : NSViewRepresentable { @Binding var text: String let placeholder: String @Binding var isFocus: Bool func makeNSView (context: Context) -> NSTextField { let tf = NSTextField () tf.focusRingType = .none tf.isBordered = false tf.isEditable = true tf.isSelectable = true tf.drawsBackground = false tf.delegate = context.coordinator tf.placeholderString = placeholder return tf } func updateNSView ( _ nsView: NSTextField, context: Context ) { nsView.font = NSFont .preferredFont(forTextStyle: .body, options: [:]) nsView.textColor = NSColor .labelColor nsView.stringValue = text } func makeCoordinator () -> FocusTextField .Coordinator { Coordinator (parent: self ) } class Coordinator : NSObject , NSTextFieldDelegate { let parent: FocusTextField init (parent: FocusTextField ) { self .parent = parent } func controlTextDidBeginEditing (_ obj: Notification) { parent.isFocus = true } func controlTextDidEndEditing (_ obj: Notification) { parent.isFocus = false } func controlTextDidChange (_ obj: Notification) { let textField = obj.object as ! NSTextField parent.text = textField.stringValue } } }
becomeFirstResponder 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class FocusAwareTextField : NSTextField { var onFocusChange: (Bool ) -> Void = { _ in } override func becomeFirstResponder () -> Bool { let textView = window?.fieldEditor(true , for : nil ) as ? NSTextView textView?.insertionPointColor = R .nsColor.action onFocusChange(true ) return super .becomeFirstResponder() } } textField.delegate func controlTextDidEndEditing (_ obj: Notification) { onFocusChange(false ) }
NSTextField and NSText https://stackoverflow.com/questions/25692122/how-to-detect-when-nstextfield-has-the-focus-or-is-its-content-selected-cocoa
When you clicked on search field, search field become first responder once, but NSText will be prepared sometime somewhere later, and the focus will be moved to the NSText.
I found out that when NSText is prepared, it is set to self.currentEditor() . The problem is that when becomeFirstResponder()’s call, self.currentEditor() hasn’t set yet. So becomeFirstResponder() is not the method to detect it’s focus.
On the other hand, when focus is moved to NSText, text field’s resignFirstResponder() is called, and you know what? self.currentEditor() has set. So, this is the moment to tell it’s delegate that that text field got focused
Use NSTextView Any time you want to customize NSTextField, use NSTextView instead
1 2 3 4 5 6 7 8 func textDidBeginEditing (_ notification: Notification) { parent.isFocus = true } func textDidEndEditing (_ notification: Notification) { parent.isFocus = false }
Updated at 2021-02-23 22:32:07