Cortado-J
Cortado-J

Reputation: 2277

How can I detect when TextField is tapped? (SwiftUI on MacOS)

How can I detect when a TextField is tapped? (SwiftUI on MacOS)

import SwiftUI

struct ContentView: View {
  @State var field: String = "TextField"
  
  var body: some View {
    TextField("Fill in Text", text: $field)
      .onTapGesture {
        print("Textfield pressed")
    }
  }
}

When the TextField is tapped it doesn't print "Textfield pressed". I'm guessing this is because the tap is picked up by the TextField before it can be detected by the Textfield gesture.

Upvotes: 7

Views: 10934

Answers (4)

Asperi
Asperi

Reputation: 258541

The .simultaneousGesture modifier does what you need.

Here is an example:

struct TestTextTap: View {
    @State var field: String = "TextField"

    var body: some View {
      TextField("Fill in Text", text: $field)
        .simultaneousGesture(TapGesture().onEnded {
          print("Textfield pressed")
        })
    }
}

Upvotes: 7

iMaddin
iMaddin

Reputation: 992

Unfortunately, .simultaneousGesture did not work for me on macOS, but what worked was to use Introspect to get the NSTextField and add a NSClickGestureRecognizer to it.

Then I added a @StateObject to handle the target/action.

Upvotes: 1

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 120133

New Method (not backward compatible)

There is a new wrapper called @FocusState that controls the state of the keyboard and the focused keyboard ('aka' firstResponder).

Detect Focused State

you can observe on the changes of the @FocusState variable with .onChange modifier

Become First Responder ( Focused )

If you use a focused modifier on the text fields, you can make them become focused, for example, you can set the focusedField property in the code to make the binded textField become active:

enter image description here

Resign first responder ( Dismiss keyboard )

or dismiss the keyboard by setting the variable to nil:

enter image description here

Don't forget to watch the Direct and reflect focus in SwiftUI session from WWDC2021


Old Method (backward compatible and forward compatible)

Instead of Taping, You can detect when TextField is focused easily inside onEditingChanged:

TextField("Fill in Text", text: $field, onEditingChanged: { focused in
    print(focused ? "focused" : "unfocused")
}

Upvotes: 8

Craig Swanson
Craig Swanson

Reputation: 105

I was able to get the intended results, but it feels slightly hacky until macOS can register a tap inside the text field.

I overlaid an almost transparent rectangle on top of the TextField. If the tap was sensed at that point, the TextField would not be selectable, but in SwiftUI you can make it the focus by using a @FocusState boolean.

So when the onTapGesture is sensed, it will change the @FocusState variable to true, which will let the user type into the TextField.

The little differences in macOS that make everything so much more complicated are maddening at times.

    @State var field: String = "TextField"
    @FocusState private var textFieldIsFocused: Bool

    var body: some View {
        TextField("Fill in Text", text: $field)
            .focused($textFieldIsFocused)
            .overlay((Color.white.opacity(0.0001)))
            .onTapGesture {
                self.textFieldIsFocused = true
                print("Textfield pressed")
            }
    }

Sorry, edited because I realized I did not include the .focused method!

Upvotes: 3

Related Questions