Marcus Rossel
Marcus Rossel

Reputation: 3258

SwiftUI Keyboard Toolbar Scope

Say we have the following view of two text fields:

struct ContentView: View {
    
    @State private var first = ""
    @State private var second = ""
    
    var body: some View {
        VStack {
            TextField("First", text: $first)
                .toolbar {
                    ToolbarItem(placement: .keyboard) {
                        Button("Test") { }
                    }
                }
            
            TextField("Second", text: $second)
        }
    }
}

The toolbar modifier is applied only to the "first" text field. My expectation is therefore that it only shows up on the keyboard, when the "first" text field is in focus. What happens in practice though, it that it also shows up when the "second" text field is in focus.

Is this intended behaviour? And if so, how can I have different keyboard toolbars for different text fields?

Upvotes: 5

Views: 2245

Answers (3)

griv
griv

Reputation: 2245

You can define a selection variable that gets set when your TextField is selected.

Then, in your .toolbar, you can check for what TextField is being edited and then display your appropriate Button.

Wrapping it in a NavigationView does work, but it also causes layout issues. This solution will also work in a ForEach loop.

struct ContentView: View {
    
    @State private var first = ""
    @State private var second = ""
    @State private var selection: Int?
    
    var body: some View {
        VStack {
            TextField("First", text: $first, onEditingChanged: { isEditing in
                self.selection = isEditing ? 1 : nil
            })
            
            TextField("Second", text: $second, onEditingChanged: { isEditing in
                self.selection = isEditing ? 2 : nil
            })
            
        }
        .toolbar {
            if selection == 1 {
                ToolbarItemGroup(placement: .keyboard) {
                    Button("Test") { }
                }
            }
        }
    }
}

Note: This seems to only work on iOS 16+

Upvotes: 1

Artem
Artem

Reputation: 413

I'm a very new to SwiftUI, but you can use the isFocused flag as a condition for adding item to the toolbar for each text field.

@FocusState private var isFirstFieldFocused: Bool
@State private var firstFieldValue: String = ""
 
var body: some View {
  TextField("First label", text: $firstFieldValue)
    .focused($isFirstFieldFocused)
    .toolbar {
      if isFirstFieldFocused {
        ToolbarItemGroup(placement: .keyboard) {...}
      }
    }
}

Upvotes: 0

sidekickr
sidekickr

Reputation: 382

The only thing that I've found so far that solves this problem works, but doesn't feel right. It also generates some layout constraint warnings in the console.

If you wrap each TextField in a NavigationView each `TextField will have its own context and thus its own toolbar.

Something like this:

struct ContentView: View {
    
    @State private var first = ""
    @State private var second = ""
    
    var body: some View {
        VStack {
          NavigationView {
            TextField("First", text: $first)
                .toolbar {
                    ToolbarItem(placement: .keyboard) {
                        Button("Test") { }
                    }
                }
          }
          NavigationView {  
            TextField("Second", text: $second)
          }
        }
    }
}

Upvotes: 1

Related Questions