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

1

10

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?

Smatter answered 3/1, 2022 at 16:50 Comment(0)
S
15

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
}
Settler answered 3/1, 2022 at 17:2 Comment(2)
This solution worked very smoothly for me as I was stuck with the same problem. Now I am able to tidy up my code. Thank you.Paternalism
Works good, but sometimes it's still more convenient to use UIKit wrapper to hide the keyboard than too look for the views to attach a gesture / adding a button for whole screen sadly :(Cheesy

© 2022 - 2024 — McMap. All rights reserved.