How do I create a multiline TextField in SwiftUI?
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
How do I create a multiline Textfiled in SwiftUI?
Here is a 90% solution. It deletes further text after the 3rd line break, but it cannot detect line wraps in long texts.
struct ContentView: View {
@State private var notes = ""
var body: some View {
VStack (alignment: .leading) {
Text("Notes")
.fontWeight(.bold)
CustomTextEditor("Enter your note", text: $notes)
}
.padding()
}
}
struct CustomTextEditor: View {
init(_ prompt: LocalizedStringKey, text: Binding<String>) {
self.prompt = prompt
self._text = Binding(projectedValue: text)
}
let prompt: LocalizedStringKey
@Binding var text: String
var body: some View {
ZStack(alignment: .topLeading ) {
Text(prompt)
.foregroundColor(text == "" ? .secondary : .clear)
.padding(EdgeInsets(top: 7, leading: 3, bottom: 0, trailing: 0))
TextEditor(text: $text)
// deleting everything after the 3rd linebreak
.onChange(of: text) { _ in
let stringArray = text.map { $0 }
let pos = stringArray.indices.filter { stringArray[$0] == "\n"}
if pos.count > 2 {
text = String(stringArray.prefix(upTo: pos[2]))
}
}
}
.frame(height: 82)
.padding(10)
.background(Color(.systemGray5))
.cornerRadius(20)
// getting rid of TextEditor standard background
.onAppear {
UITextView.appearance().backgroundColor = .clear
}
.onDisappear {
UITextView.appearance().backgroundColor = .systemGray5
}
}
}
How to create a multiline UITextfield?
UITextField
is specifically one-line only.
Your Google search is correct, you need to use UITextView
instead of UITextField
for display and editing of multiline text.
In Interface Builder, add a UITextView
where you want it and select the "editable" box. It will be multiline by default.
Rich TextView in SwiftUI
There is a well documented library that for SwiftUI text editor. it supports iOS 13.0+ and macOS 10.15+, here is the link for it!
HighlightedTextEditor
It's also very simple to use.
SwiftUI Wrapper for UITextView not updating ObservedObject
Your multiline text view needs a coordinator to observe the text updates from UITextView
struct MultilineTextView: UIViewRepresentable {
@ObservedObject var myOText: MyOText
func makeUIView(context: Context) -> UITextView {
let view = UITextView()
view.isScrollEnabled = true
view.isEditable = true
view.isUserInteractionEnabled = true
view.textAlignment = .center
view.font = UIFont(name: "Times New Roman", size: 20)
view.delegate = context.coordinator
return view
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = myOText.inTheCourse
}
func makeCoordinator() -> MultilineTextView.Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextViewDelegate {
var control: MultilineTextView
init(_ control: MultilineTextView) {
self.control = control
}
func textViewDidChange(_ textView: UITextView) {
control.myOText.inTheCourse = textView.text
}
}
}
Related Topics
iOS 12 Errors: Appears to Be from a Different Nsmanagedobjectmodel Than This Context'S
Cannot Preview in This File -- Message Send Failure
How to Convert Tuple to Anyobject in Swift
Swiftui: Update Navigationview After Deletion (Ipad)
Subclass Uiscrollview in Swift for Touches Began & Touches Moved
Margin Between Images in Uiscrollview
Creating a Type Bound to a Certain Range in Swift
Scntext Alignment Not Working in iOS
How to Prevent a Spacer to Make a VStack Greedly Grow Beyond Necessary
Build Error in Xcode on Cloud-Hosted MAC on VSts
How to Cast an @Binding in Swift
How to Implement a Swift Protocol Across Structs with Conflicting Property Names
Select All Text in a Nstextfield Using Swift
Glkit VS. Metal Perspective Matrix Difference
How to Change Default Background Color of Callout Bubble with Detailcalloutaccessoryview
Anonymous User in Realm Mobile Platform