swiftuiparent-child

How should I get FocusState from ChildView to ParentView in SwiftUI?


I have a problem how to deal with FocusState in my project.

My parent View has an enum created on top:

enum RegistrationFocus: Hashable {
case username, password, confirmPassword, nameAndSurname, email, confirmEmail, phoneNumber
}

And I have a focusState variable inside my struct

@FocusState var focus: RegistrationFocus?

My childview is in a VStack to display all views. (only wrote 3 down there for now)

PersonalUserDetailsRow(title: "UserName", text: $registerModel.username, textContentType: .username, focus: $focus, focusfield: .username)
PersonalUserDetailsRow(title: "Password", text: $registerModel.password, textContentType: .newPassword, focus: $focus, focusfield: .password)
PersonalUserDetailsRow(title: "Confirm Password", text: $registerModel.confirmPassword, textContentType: .confirmPassword focus: $focus, focusfield: .confirmPassword)

And my ChildView looks like this:

struct PersonalUserDetailsRow: View {

var title: String
@Binding var text: String
let textContentType: UITextContentType
var focus: FocusState<RegistrationFocus?>.Binding
@State var focusField: RegistrationFocus?

var body: some View {

if textContentType == .newPassword {

SecureField(title, text: $text)

.padding(.top, 15)

.disableAutocorrection(true)

.textContentType(textContentType)

.focused(focus.projectedValue, equals: focusField)

Divider() .overlay(Color.black)

So my child view does contain var focus: FocusState<RegistrationFocus?>.Binding and State focusField: RegistrationFocus? But I have no clue how to use those 2. I want to go to the next textField when the user taps the return key on keyboard.

I have seen many examples where people use 2 textfields in Parent view and i understand those examples and how to move around textFields when using .focused(, equals:).

But I can't find any examples how to do this with a child View, especially with this .focused(focus.projectedValue, equals: focusField) if it's even correct.

How should I do this so it will work? I keep getting this error:

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions. with the above code

I tried both of these:

var focus: FocusState<RegistrationFocus?>.Binding
@State var focusField: RegistrationFocus?

@binding var focusField doesn't work.

I don't really want to copy paste the textField and Divider() from child view 7 times in my parents view. I want to learn how to use the custom view with FocusState in my parents view.


Solution

  • Change PersonalUserDetailsRow to set the next focus field when the field value is set:

    struct PersonalUserDetailsRow: View {
    
    var title: String
    @Binding var text: String
    // let textContentType: UITextContentType
    @Binding var focus: RegistrationFocus?
    let focused: RegistrationFocus
    let nextFocused: RegistrationFocus
    
    var body: some View {
    
    // if textContentType == .newPassword {
    
    SecureField(title, text: $text)
    
        .onSubmit {
            focus = nextFocused
        }
    
    .padding(.top, 15)
    
    .disableAutocorrection(true)
    
    // .textContentType(textContentType)
    
    .focused($focus, equals: focused)
    
    

    Put into the initialiser the NEXT field you want to focus:

    PersonalUserDetailsRow(title: "UserName", text: $registerModel.username, textContentType: .username, focus: $focus, focused: .username, nextFocused: .password)