It is possible to accessing FocusState's value outside of the body of a View

Viewed 619

I want to deport my @FocusState into my viewModel:

struct ContentView: View {
    @ObservedObject private var viewModel = ViewModel()
    
    var body: some View {
        Form {
            TextField("Text", text: $viewModel.textField)
                .focused(viewModel.$hasFocus)
            Button("Set Focus") {
                viewModel.hasFocus = true
            }
        }
    }
}

class ViewModel: ObservableObject {
    @Published var textField: String = ""
    @FocusState var hasFocus: Bool
}

But when I launch my app, i have this SwiftUI warning:

runtime: SwiftUI: Accessing FocusState's value outside of the body of a View. This will result in a constant Binding of the initial value and will not update.

And in this case, my binding is never changed.

My question is: It is possible to use FocusState in a viewModel?

1 Answers

It is in-view wrapper (same as State). But it is possible to map it to published property like in below approach.

Tested with Xcode 13.2 / iOS 15.2

struct ContentView: View {
    @ObservedObject private var viewModel = ViewModel()
    @FocusState var hasFocus: Bool

    var body: some View {
        Form {
            TextField("Text", text: $viewModel.textField)
                .focused($hasFocus)
                .onChange(of: viewModel.hasFocus) {
                    hasFocus = $0
                }
                .onChange(of: hasFocus) {
                    viewModel.hasFocus = $0
                }
            Button("Set Focus") {
                viewModel.hasFocus = true
            }
        }
    }
}

class ViewModel: ObservableObject {
    @Published var textField: String = ""
    @Published var hasFocus: Bool = false
}
Related