1

I am using a multiline text field that wraps the text vertically to new lines. Is there a way to adjust the padding for the wrapped lines, not including the first line? I am trying to have subsequent lines use a negative leading padding, or more generally, have them appear right under the Text("Word").

HStack(alignment: .top) {
    Text("Word")
        .foregroundColor(.black)
        .padding(.top, 8)

    TextField("", text: $PresentationManager.entryText, prompt: Text("required"), axis: .vertical)
        .foregroundColor(.black)
        .focused($isTextFieldFocused)
        .background(Color.clear)
        .padding(.top, 8)
        .multilineTextAlignment(.leading)
}

In the image below, I am trying to get the second line of the wrapped text to have less padding while maintaining the positioning of the first line of the entry.

enter image description here

1
  • Are you planning to add different style for the Text("Word") View?
    – Carsten
    Commented May 30 at 9:49

1 Answer 1

1

One way to achieve this would be to use a ZStack to superimpose the TextField over the Text, then add leading spaces to the text being entered.

  • An .onChange handler can be used to prevent the user from deleting the leading spaces.

  • You will need to be aware, that the resulting input will include leading spaces. However, you could handle this by copying the trimmed text to your actual state property.

  • The prompt text will need to be improvised, because the input does not start empty. One way would be to show the text in the background, using the same leading spaces. The opacity of this text can depend on whether the trimmed input is empty or not.

struct ContentView: View {
    private let leadingSpaces = "             "
    @State private var entryText = ""
    @FocusState private var isTextFieldFocused: Bool

    var body: some View {
        ZStack(alignment: .topLeading) {
            Text("Word")
                .foregroundStyle(.black)
                .padding(.top, 8)

            TextField("", text: $entryText, axis: .vertical)
                .foregroundStyle(.black)
                .focused($isTextFieldFocused)
                .background(alignment: .topLeading) {
                    (Text(leadingSpaces) + Text("required"))
                        .foregroundStyle(.placeholder)
                        .opacity(entryText.trimmingCharacters(in: .whitespaces).isEmpty ? 1 : 0)
                }
                .padding(.top, 8)
                .multilineTextAlignment(.leading)
                .onChange(of: entryText, initial: true) { oldVal, newVal in
                    let trimmedText = newVal.drop { $0 == " " }
                    if !newVal.hasPrefix(leadingSpaces) {
                        entryText = leadingSpaces + trimmedText
                    }
                    // PresentationManager.entryText = String(trimmedText)
                }
        }
        .border(.red)
        .padding(32)
    }
}

Screenshot

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.