Input/Display Multiline TextField
Published by @SoNiceInfo at 6/24/2020
iOS 14 Support
For inputting multiple lines text, TextEditor has been added in the new SwiftUI in WWDC20.
We don't need to use UITextView wrapped by SwiftUI any more. Using Text and lineLimit(nil) modifier to get multiple lines to display.
import SwiftUI
struct ContentView: View {
@State var text: String = ""
var body: some View {
VStack {
// Input
TextEditor(text: $text)
.frame(width: UIScreen.main.bounds.width * 0.8, height: 200)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.blue, lineWidth: 5)
)
// Display
Text(text)
.foregroundColor(.yellow)
.lineLimit(nil)
.padding(5)
.frame(width: UIScreen.main.bounds.width * 0.8, height: 200, alignment: .topLeading)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.green, lineWidth: 5)
)
}
}
}iOS 13 Support
To display more than one text, use the Text and lineLimit(nil) modifier to get multiple lines.
But we can't make TextField of multiple lines with them.
So we use UIViewRepresentable to arrange UITextView so that we can use it in SwiftUI.
Prepare MultilineTextField Struct
struct MultilineTextField: UIViewRepresentable {
@Binding var text: String
}Creating a MultilineTextField that supports multi-line text input.
Conforms to the UIViewRepresentable protocol.
We can now use UITextView.
The MultilineTextField also takes the binding variable text and makes it available for reference and modification.
Creating a Text Field with UITextView
struct MultilineTextField: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
let view = UITextView()
view.isScrollEnabled = true
view.isEditable = true
view.font = UIFont.systemFont(ofSize: 18)
return view
}
func updateUIView(_ uiView: UITextView, context: Context) {
if uiView.text != text {
uiView.text = text
}
}
}Next, implementing makeUIView and updateUIView.
Creating UITextView instance at makeUIView.
Apply view.isScrollEnabled = true for Scrollability, view.isEditable = true for editable.
In updateUIView, if the text variable is changed, the contents of the MultilineTextField are also changed.
Notify Parent View for Text Changing
struct MultilineTextField: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
view.delegate = context.coordinator
return view
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator : NSObject, UITextViewDelegate {
var parent: MultilineTextField
init(_ textView: MultilineTextField) {
self.parent = textView
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return true
}
func textViewDidChange(_ textView: UITextView) {
self.parent.text = textView.text
}
}
}A change notification of the variable text modified is not sent to the parent View by default.
Use Coordinator to notify the parent view of changes from the child view.
Don't forget to add delegate = context.coordinator in makeUIView.
Completion
MultilineTextField are called like TextField() with MultilineTextField(text: $text).
View modifier is also available.
Blue area is MultilineTextField(text: $text), result is displayed in green area.
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
@State var text: String = ""
var body: some View {
VStack {
// Input
MultilineTextField(text: $text)
.frame(width: UIScreen.main.bounds.width * 0.8, height: 200)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.blue, lineWidth: 5)
)
// Display
Text(text)
.foregroundColor(.yellow)
.lineLimit(nil)
.padding(5)
.frame(width: UIScreen.main.bounds.width * 0.8, height: 200, alignment: .topLeading)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.green, lineWidth: 5)
)
}
}
}
// TextFiled for multi line supported.
struct MultilineTextField: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
let view = UITextView()
view.delegate = context.coordinator
view.isScrollEnabled = true
view.isEditable = true
view.isUserInteractionEnabled = true
view.font = UIFont.systemFont(ofSize: 18)
return view
}
func updateUIView(_ uiView: UITextView, context: Context) {
if uiView.text != text {
uiView.text = text
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator : NSObject, UITextViewDelegate {
var parent: MultilineTextField
init(_ textView: MultilineTextField) {
self.parent = textView
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return true
}
func textViewDidChange(_ textView: UITextView) {
self.parent.text = textView.text
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Please see how to close keyboard here.
Close Keyboard
References
ios - How do I create a multiline TextField in SwiftUI? - Stack OverflowSwiftUI Multiline Text - Swiftly Dierkes

