1

I'm using a TextEditor inside a Form. A minimal playground example would be

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    @State var text = String()
    
    var body: some View {
        Form {
            Section("Section") {
                Toggle("Toggle", isOn: .constant(true))
                LabeledContent("TextEditor") {
                    TextEditor(text: $text)
                }
            }
        }
    }
}
PlaygroundPage.current.setLiveView(ContentView())

This renders into something like:

TextEditor with extend of a single line

As TextEditor is a multiline input field, I'd like it to extend to the remaining available space on the screen, so something like

TextEditor extending to end of screen

I can achieve this by adding a .frame(height:540) modifier to the TextEditor, however this hardcodes the extend is not very dynamic and thus only works on a specific device.

So the question is, how to to this in a dynamic way which works on all potential devices (different iPhones, iPad, ...).

Note: This question is similar to SwiftUI Texteditor in a form. However this only addresses the issue how to get it to show multiple lines, which can be easily achieved using the above mentioned .frame(height:X) modifier.

Tobias Müller
  • 585
  • 1
  • 4
  • 21

1 Answers1

0

I don't think this is the best solution, although it works. If you want something else, try using GeometryReader with a dynamic height value stored in a CGFloat variable. (Tested on iPhone 14 Pro, 14 Pro Max and iPad 12.9 inch)

UISCREEN SOLUTION

import SwiftUI

struct ContentView: View {
    @State var text = String()
    
    var body: some View {
        if #available(iOS 16, *){
            Form {
                Section("Section") {
                    Toggle("Toggle", isOn: .constant(true))
                    LabeledContent("TextEditor") {
                        TextEditor(text: $text)
                    }.frame(minHeight: UIScreen.main.bounds.maxY-190)
                }
            }
        }
    }
}

You can also use constant points, as the points reflect different screen sizes and resolutions: https://stackoverflow.com/a/73653966/14856451

GEOMETRY READER SOLUTION

@State var text = String()
@Environment(\.defaultMinListRowHeight) var minH
var body: some View {
    if #available(iOS 16, *){
        GeometryReader {geometry in
            Form {
                Section("Section") {
                    Toggle("Toggle", isOn: .constant(true))
                    LabeledContent("TextEditor") {
                        TextEditor(text: $text)
                    }.frame(minHeight: geometry.size.height-minH-70)
                }
            }
        }
    }
}

Notice the blue outline - that's the size of your form. As you can see in all three cases, the TextField reaches the bottom of the form without going into the safe zone, which is used to control gestures on the device (there are no gestures on the iPhone SE, so there is no safe zone either).

enter image description here enter image description here enter image description here

Isaac
  • 368
  • 4
  • 12
  • The solution with the difference to UIScreen.main.bounds.maxY doesn't work well for me. It looks quite different on iPhone 14 Pro, iPhone SE and iPad 12.9 for me. However the GeometryReader was a very good hint. I'll investigate that further. – Tobias Müller Feb 20 '23 at 06:47
  • @TobiasMüller, I think you can make the minimum form row height static, like 44, and then use GeometryReader to calculate the whole form height and subtract 44. Check the effect of .environment(\.defaultMinListRowHeight, 44) on the Form/List/ScrollView. – Isaac Feb 20 '23 at 09:24
  • The update example with the GeometryReader works like a charm. Especially like the defaultMinListRowHeight default. Thanks a lot! – Tobias Müller Feb 21 '23 at 12:19