I wanted to have some TextEditor
in my ForEach and I made this sample code in down! As you can see the code and result of it in Image, TextEditor
act like a greedy view, and takes all available space! which has so many downsides for me at least!
If I go and limit the hight to a custom value then I would loss the possibility of seeing all strings and lines of strings of TextEditor in itself and I must scroll up or down for seeing other lines, which is not my design!
My goal is that the TextEditor
takes the space as it needs and if I enter new line of string then it can grow in height or if I remove the lines of strings it can shrinks in height to minimum of 1 line at least!
I wonder how can I do this?
struct ContentView: View {
@StateObject var textEditorReferenceType: TextEditorReferenceType = TextEditorReferenceType()
var body: some View {
Text("TextEditorView").bold().padding()
VStack {
ForEach(textEditorReferenceType.arrayOfString.indices, id: \.self, content: { index in
TextEditorView(string: $textEditorReferenceType.arrayOfString[index])
})
}
.padding()
}
}
struct TextEditorView: View {
@Binding var string: String
var body: some View {
TextEditor(text: $string)
.cornerRadius(10.0)
.shadow(radius: 1.0)
}
}
class TextEditorReferenceType: ObservableObject {
@Published var arrayOfString: [String] = ["Hello, World!", "Hello, World!", "Hello, World!"]
}
In iOS 16 it's now natively possible with a regular textField
by adding axis: .vertical
and .lineLimit()
linelimit defines the number of lines until the textfield extends. Add a range to start to define a range of lines within the textfield will start and stop to extend.
WWDC22 Session "What'S new in SwiftUI around 17:10
You can use a PreferenceKey
and an invisible Text
overlay to measure the string dimensions and set the TextEditor
's frame:
struct TextEditorView: View {
@Binding var string: String
@State var textEditorHeight : CGFloat = 20
var body: some View {
ZStack(alignment: .leading) {
Text(string)
.font(.system(.body))
.foregroundColor(.clear)
.padding(14)
.background(GeometryReader {
Color.clear.preference(key: ViewHeightKey.self,
value: $0.frame(in: .local).size.height)
})
TextEditor(text: $string)
.font(.system(.body))
.frame(height: max(40,textEditorHeight))
.cornerRadius(10.0)
.shadow(radius: 1.0)
}.onPreferenceChange(ViewHeightKey.self) { textEditorHeight = $0 }
}
}
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value, nextValue: () -> Value) {
value = value + nextValue()
}
}
Adapted from my other answer here: Mimicking behavior of iMessage with TextEditor for text entry
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With