swiftuifocusproperty-wrapper

Passing down @FocusState to another view


I was wondering how would I be able to pass down a @FocusState to another view. Here is some example code:

struct View1: View {
    enum Field {
        case username, password
    }
    
    @State var passwordText: String = ""
    @FocusState var focusedField: Field?
    
    var body: some View {
        // How would I be able to pass the focusedField here?
        View2(text: $passwordText, placeholder: "Password")
        
        //TextField("Password", text: $passwordText)
        //.frame(minHeight: 44)
        //.padding(.leading, 8)
        //.focused($focusedField, equals: .password)
        
        // How would I be able to add the commented code above to View2?
    }
}

struct View2: View {
    @Binding var text: String
    let placeholder: String
    
    var body: some View {
        HStack {
            TextField(placeholder, text: $text)
                .frame(minHeight: 44)
                .padding(.leading, 8)
            // How would I be able to add this
            //.focused(binding: , equals: )
            if text.count > 0 {
                Image(systemName: "xmark.circle.fill")
                    .font(.headline)
                    .foregroundColor(.secondary)
                    .padding(.trailing, 8)
            }
        }
    }
}

How would I be able to pass it down to View2?
Or is there a better way to reuse a custom text field?


Solution

  • You can pass its binding as argument, like

    struct View1: View {
      enum Field {
        case username, password
      }
    
      @State var passwordText: String = ""
      @FocusState var focusedField: Field?
    
      var body: some View {
        View2(text: $passwordText, placeholder: "Password", focused: $focusedField)
      }
    }
    
    struct View2: View {
      @Binding var text: String
      let placeholder: String
      var focused: FocusState<View1.Field?>.Binding     // << here !!
    
      var body: some View {
        HStack {
            TextField(placeholder, text: $text)
                .frame(minHeight: 44)
                .padding(.leading, 8)
                .focused(focused, equals: .password)     // << here !!
            if text.count > 0 {
                Image(systemName: "xmark.circle.fill")
                    .font(.headline)
                    .foregroundColor(.secondary)
                    .padding(.trailing, 8)
            }
    
        }
      }
    }