Search code examples
iosswiftuifocustextfield

Detect `FocusState` changes in reusable TextField composite views


I would like to create a reusable view that embeds a TextField and a visual indicator (underline Rectangle) view that changes color when the TextField is editing (i.e. has focus).

In an example container view, I may have several of these reusable views, and I'm using the FocusState pattern like so:

private enum FocusedField {
    case first
    case second
    case third
}

@FocusState private var focusedField: FocusedField?

MyCustomTextField(...)
    .focused($focusedField, equals: .second)

In general, this works. Focus will shift to the custom text field even though it's inside a container view with the TextField and a Rectangle(...). (Not really sure I understand how this is working, tbh)

However, I don't know how to generically have the Rectangle change color based on whether or not the associated TextField has focus.

The rectangle is just:

    Rectangle()
        .fill(isFocused ? Color.blue : Color.gray)
        .frame(maxWidth: .infinity, minHeight: 2, maxHeight: 2)
        .padding(.horizontal)

Any guidance appreciated.


Solution

  • Just use internally own FocusState, it does not conflict with external

    demo

    struct MyCustomTextField: View {
        @Binding var text: String
        @FocusState var isFocused       // << internal
    
        var body: some View {
            TextField("", text: $text)
                .focused($isFocused)     // << get state
                .padding()
                .background(
                    Rectangle()
                        .fill(isFocused ? Color.blue : Color.gray)  // !!
                        .frame(maxWidth: .infinity, minHeight: 2, maxHeight: 2)
                        .padding(.horizontal)
                , alignment: .bottom)
        }
    }
    

    Tested with Xcode 13.4 / iOS 15.5

    Test module on GitHub