SwiftUI FocusState does not work on other views with TabView

162 Views Asked by At

I have a view with a TabView that contains three different views. If I focus on the TextField in the first view, a Done button appears above the keyboard. But in the second and third view, no Done button appears above the keyboard when I take the TextField into focus.

import SwiftUI

struct TabViewTest: View {
    var body: some View {
        TabView {
            
            ViewOne()
                .tabItem {
                    Image(systemName: "1.circle")
                }
            
            ViewTwo()
                .tabItem {
                    Image(systemName: "2.circle")
                }
            
            ViewThree()
                .tabItem {
                    Image(systemName: "3.circle")

                }
        }
    }
}

#Preview {
    TabViewTest()
}

import SwiftUI

struct ViewOne: View {
    
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    var body: some View {
        NavigationStack {
            VStack {
                Text("Text 1")
                TextField("Text 1", text: $text)
                    .focused($isFocused)
                    
                
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = false
                    }
                }
            }
        }
    }
}

#Preview {
    ViewOne()
}

import SwiftUI

struct ViewTwo: View {
    @State private var text: String = ""
    @FocusState private var isFocused: Bool
    var body: some View {
        NavigationStack {
            VStack {
                Text("Text 2")
                TextField("Text 2", text: $text)
                    .focused($isFocused)
                    
                
            }
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = false
                    }
                }
            }
        }
    }
}


#Preview {
    ViewTwo()
}

Problem Video

I tried to give each view its own FocusState, but that didn't solve the problem.

1

There are 1 best solutions below

0
On

If you're looking to manage focus across multiple views in SwiftUI, one approach is to use a shared @FocusState. Here's a simplified example:

Define a Focus Enum: Create an enum to identify different text fields.

enum FocusedField {
    case firstField, secondField
}

Use a Shared @FocusState in Parent View: In your main view (ContentView), declare a @FocusState variable. This state is then passed to the child views.

@FocusState private var isFocused: FocusedField?

Inject the @FocusState into Child Views: Pass the @FocusState to child views (ViewOne and ViewTwo) as a binding.

ViewOne(isFocused: _isFocused)

Manage Focus in Child Views: In each child view, use the passed @FocusState to control the focus of the text fields.

@FocusState var isFocused: FocusedField?

This method allows you to centrally manage the focus state from the parent view, making it easier to control keyboard interactions across different views in a TabView.

Here is the full code example:

import SwiftUI

enum FocusedField {
    case firstField, secondField
}

struct ContentView: View {
    
    @FocusState private var isFocused: FocusedField?
    
    var body: some View {
        TabView {
            ViewOne(isFocused: _isFocused)
                .tabItem {
                    Image(systemName: "1.circle")
                }
            ViewTwo(isFocused: _isFocused)
                .tabItem {
                    Image(systemName: "2.circle")
                }
        }
        .toolbar {
            ToolbarItemGroup(placement: .keyboard) {
                Spacer()
                Button("Done") {
                    isFocused = nil
                }
            }
        }
    }
}

struct ViewOne: View {
    
    @FocusState var isFocused: FocusedField?
    @State private var text: String = ""
    
    var body: some View {
        NavigationStack {
            VStack {
                TextField("Textfield 1", text: $text)
                    .focused($isFocused, equals: FocusedField.firstField)
            }
            .navigationTitle("View One")
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = nil
                    }
                }
            }
        }
    }
}

struct ViewTwo: View {
    @FocusState var isFocused: FocusedField?
    @State private var text: String = ""
    
    var body: some View {
        NavigationStack {
            VStack {
                TextField("Textfield 2", text: $text)
                    .focused($isFocused, equals: FocusedField.secondField)
            }
            .navigationTitle("View Two")
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    Button("Done") {
                        isFocused = nil
                    }
                }
            }
        }
    }
}

#Preview {
    ContentView()
}