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