Search code examples
iosswiftswiftuiswiftui-texteditor

All TextEditor are resized when any TextEditor has more than one line


I have a problem. I have a view with several TextEditors. Typing in any of them changes the height of all of them.

Do you have any idea what happens and how to fix it?

Example Code:

    import SwiftUI

    struct TestingView: View {

        @State var optionA = ""
        @State var optionB = ""

        @State private var comment = ""
        
        var body: some View {
            NavigationStack {
                Form {
                    VStack() {
                        CustomRow(title: "Option A", value: $optionA)
                        CustomRow(title: "Option B", value: $optionB)
                    }
                    .padding(.vertical, 20)
                }
                .navigationTitle("Testing View")
                .padding(.zero)
            }
        }
    }

    struct CustomRow: View {

        var title: String = ""
        @Binding var value: String

        var body: some View {
            VStack(alignment: .leading) {
                Text(title)
                    .font(.system(.headline, design: .rounded))
                    .foregroundColor(.gray)
                    .listRowSeparator(.hidden)

                ZStack {
                    TextEditor(text: $value)
                        .padding(4)
                        .autocapitalization(.none)
                        .disableAutocorrection(true)
                        .textFieldStyle(.roundedBorder)
                        .font(.system(.body, design: .rounded))
                        .frame(minHeight: 50, maxHeight: 200)

                }
                .overlay(
                    RoundedRectangle(cornerRadius: 4)
                        .stroke(.gray, lineWidth: 1)
                )
            }
            .padding(.bottom, 10)
        }
    }

    struct TestingView_Previews: PreviewProvider {
        static var previews: some View {
            TestingView()
        }
    }

Solution

  • I think this is because VStacks try to layout its views by distributing them equally along the vertical axis, whenever it can. Since you gave the text editors a flexible height between 50 and 200, they can be stretched so that both text editors are equally tall.

    From trial and error, you can fix this by adding a vertical fixedSize to the VStack:

    VStack() {
        CustomRow(title: "Option A", value: $optionA)
        CustomRow(title: "Option B", value: $optionB)
    }
    .padding(.vertical, 20)
    .fixedSize(horizontal: false, vertical: true)
    

    But I would just do this as two separate rows of the form, and hide the list separator. If you want the vertical padding, add them separately to each CustomRow:

    Form {
        Group {
            CustomRow(title: "Option A", value: $optionA)
                .padding(.top, 20)
            CustomRow(title: "Option B", value: $optionB)
                .padding(.bottom, 20)
        }
        .listRowSeparator(.hidden)
    }
    .navigationTitle("Testing View")
    .padding(.zero)