How do you create a multi-line text inside a ScrollView in SwiftUI?
In Xcode 11 GM:
For any Text
view in a stack nested in a scrollview, use the .fixedSize(horizontal: false, vertical: true)
workaround:
ScrollView {
VStack {
Text(someString)
.fixedSize(horizontal: false, vertical: true)
}
}
This also works if there are multiple multiline texts:
ScrollView {
VStack {
Text(someString)
.fixedSize(horizontal: false, vertical: true)
Text(anotherLongString)
.fixedSize(horizontal: false, vertical: true)
}
}
If the contents of your stack are dynamic, the same solution works:
ScrollView {
VStack {
// Place a single empty / "" at the top of your stack.
// It will consume no vertical space.
Text("")
.fixedSize(horizontal: false, vertical: true)
ForEach(someArray) { someString in
Text(someString)
.fixedSize(horizontal: false, vertical: true)
}
}
}
Multiline text truncated in ScrollView
With the help of concepts from the answer from Tushar Sharma I was able to create a version that displays the multiline text and has a continuous divider between the two "columns".
The only changes are in SomeRow View (compared to my initial question):
struct SomeRow: View {
var entries: [Entry]
var body: some View {
VStack(alignment: .leading, spacing: 0){
Text("title").frame(maxWidth: .infinity, alignment: .leading)
Spacer().frame(height: 5)
ForEach(entries){entry in
HStack(alignment: .top){
VStack{
Text("00:00 - 00:00")
Spacer()
}.frame(minWidth: 110)
Divider()
VStack(alignment: .leading){
Text("titleinner")
HStack(alignment: .lastTextBaseline){
Text(entry.description ?? "")
Spacer()
Text("number")
}
Spacer()
}
Spacer()
}.fixedSize(horizontal: false, vertical: true)
}
}
}
}
Basically using specified alignments and using fixedSize on the whole container of the text works wonders.
This is how it looks like now:
Trying to set up a scrollable view with multiple multiline of text but when app is run, it is running very slow when scrolling
I think the problem is with your padding()
s. try removing them.
You should add padding to your views like this:
Text("content")
.padding()
as you can see in the documentation, padding(_)
is a view modifier and should be called on a View
.
to add extra space between your components, you can do either:
1- set the space between components of your LazyVStack
by passing spacing
like this:
LazyVStack(alignment: .leading, spacing: 32) { // <- spacing
Text("Main Screen")
.font(.title2)
.foregroundColor(.purple)
Text("This is the description text for the Main Screen")
.padding(.all)
.font(.title3)
.foregroundColor(.pink)
}.padding(.leading)
2- or set the top padding by using padding(_, _)
modifier:
LazyVStack(alignment: .leading) {
Text("Main Screen")
.font(.title2)
.foregroundColor(.purple)
.padiing(.top, 32) // <-- padding
Text("This is the description text for the Main Screen")
.padding(.all)
.font(.title3)
.foregroundColor(.pink)
.padding(.top, 32) // <-- padding
}.padding(.leading)
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
Adding unlimited lines in a Text (SwiftUI)
For wrapping Text in a Form .lineLimit(Int.max)
did not work for me. It seems there needs to be some width for it to know when to wrap. I believe the official way is with .fixedSize
:
Text(message)
.fixedSize(horizontal: false, vertical: true)
The documentation states:
This example shows the effect of fixedSize(horizontal:vertical:) on a text view that is wider than its parent, preserving the ideal, untruncated width of the text view.
https://developer.apple.com/documentation/swiftui/view/fixedsize(horizontal:vertical:)
Related Topics
How to Add Type Constraints to a Swift Protocol Conformance Extension
How to Use Special Character in Nsurl
Wait Until Swift For Loop With Asynchronous Network Requests Finishes Executing
Trying to Understand Asynchronous Operation Subclass
Using Decodable in Swift 4 With Inheritance
Accessing an Enumeration Association Value in Swift
Swift: Print() VS Println() VS Nslog()
Sort Dictionary by Values in Swift
Waiting Until the Task Finishes
Passing an Array to a Function With Variable Number of Args in Swift
How to Enumerate an Enum With String Type
How to Store 1.66 in Nsdecimalnumber
How to Create Usdz File Using Xcode Converter
How Does String Substring Work in Swift
How to Easily Duplicate/Copy an Existing Realm Object
Difference Between Computed Property and Property Set With Closure