Search code examples
iosswiftuitextviewtextfield

How do I create a multiline TextField in SwiftUI?


I've been trying to create a multiline TextField in SwiftUI, but I can't figure out how.

This is the code I currently have:

struct EditorTextView : View {
    @Binding var text: String
    
    var body: some View {
        TextField($text)
            .lineLimit(4)
            .multilineTextAlignment(.leading)
            .frame(minWidth: 100, maxWidth: 200, minHeight: 100, maxHeight: .infinity, alignment: .topLeading)
    }
}

#if DEBUG
let sampleText = """
Very long line 1
Very long line 2
Very long line 3
Very long line 4
"""

struct EditorTextView_Previews : PreviewProvider {
    static var previews: some View {
        EditorTextView(text: .constant(sampleText))
            .previewLayout(.fixed(width: 200, height: 200))
    }
}
#endif

But this is the output:

enter image description here


Solution

  • Update: While Xcode11 beta 4 now does support TextView, I've found that wrapping a UITextView is still be best way to get editable multiline text to work. For instance, TextView has display glitches where text does not appear properly inside the view.

    Original (beta 1) answer:

    For now, you could wrap a UITextView to create a composable View:

    import SwiftUI
    import Combine
    
    final class UserData: BindableObject  {
        let didChange = PassthroughSubject<UserData, Never>()
    
        var text = "" {
            didSet {
                didChange.send(self)
            }
        }
    
        init(text: String) {
            self.text = text
        }
    }
    
    struct MultilineTextView: UIViewRepresentable {
        @Binding var text: String
    
        func makeUIView(context: Context) -> UITextView {
            let view = UITextView()
            view.isScrollEnabled = true
            view.isEditable = true
            view.isUserInteractionEnabled = true
            return view
        }
    
        func updateUIView(_ uiView: UITextView, context: Context) {
            uiView.text = text
        }
    }
    
    struct ContentView : View {
        @State private var selection = 0
        @EnvironmentObject var userData: UserData
    
        var body: some View {
            TabbedView(selection: $selection){
                MultilineTextView(text: $userData.text)
                    .tabItemLabel(Image("first"))
                    .tag(0)
                Text("Second View")
                    .font(.title)
                    .tabItemLabel(Image("second"))
                    .tag(1)
            }
        }
    }
    
    #if DEBUG
    struct ContentView_Previews : PreviewProvider {
        static var previews: some View {
            ContentView()
                .environmentObject(UserData(
                    text: """
                            Some longer text here
                            that spans a few lines
                            and runs on.
                            """
                ))
    
        }
    }
    #endif
    

    enter image description here