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.
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)
}
}