How to force two lines of Text in SwiftUI
Table of Contents
SwiftUI Text will take as many lines as possible to render its content by default. If you want, you can limit the number of lines with .lineLimit(_:)
modifier, but we have no way to set minimum lines.
If you have a layout that needs to be present at an equal height, this might be a problem.
Consider this product card view with a varied name length. If you want to present them side by side in a grid, you might want them to have the same height.
Today, I'm going to show you a quick and dirty hack to set a minimum text line for a text view.[1]
How to set a minimum number of lines to a text view
To force a minimum number of lines to a text view, you append a new line character (\n
) to your text.
Here is my ProductCard
view.
struct ProductCard: View {
let imageName: String
let name: String
let chef: String
let price: String
var body: some View {
VStack {
Image(imageName)
.resizable()
.scaledToFill()
.frame(width: 150, height: 150)
.clipShape(Circle())
.shadow(radius: 10)
VStack(alignment: .leading, spacing: 4) {
Text(name)
.lineLimit(2)
.font(.title.bold())
Text("by \(chef)")
.bold()
.foregroundColor(.gray)
HStack {
Text("$\(price)")
.font(.headline.bold())
.padding(.top, 8)
}
}.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(20)
.frame(width: 250)
.background()
.cornerRadius(8)
.shadow(radius: 10)
}
}
To force product name to always render as two lines, I modify Text(name)
to Text(name + "\n")
.
struct ProductCard: View {
let imageName: String
let name: String
let chef: String
let price: String
var body: some View {
VStack {
Image(imageName)
.resizable()
.scaledToFill()
.frame(width: 150, height: 150)
.clipShape(Circle())
.shadow(radius: 10)
VStack(alignment: .leading, spacing: 4) {
Text(name + "\n")
.lineLimit(2)
.font(.title.bold())
Text("by \(chef)")
.bold()
.foregroundColor(.gray)
HStack {
Text("$\(price)")
.font(.headline.bold())
.padding(.top, 8)
}
}.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(20)
.frame(width: 250)
.background()
.cornerRadius(8)
.shadow(radius: 10)
}
}
As simple as that, my product card views are now rendered at the same height.
Solution
The solution can sum up as follows:
To force text to have minimum n
lines, you append n-1
new line characters to your text.
And you should limit the number of lines to n
with .lineLimit(_:)
.
// Force 2 lines
Text(name + "\n")
.lineLimit(2)
// Force 3 lines
Text(name + "\n\n")
.lineLimit(3)
You can easily support sarunw.com by checking out this sponsor.
Localization Buddy: Easiest way to localize and update App Store metadata.
Caveat
Since this is quite a hack, you can expect a drawback. If your product name takes two lines, it will render in truncated form (showing ellipsis).
ProductCard(
imageName: "soup2",
name: "Delicious breakfast",
chef: "Monika Grabkowska",
price: "5.99")
Typically, "Delicious breakfast" should fit perfectly without an ellipsis, but since we add an extra line with a newline character (\n
), that makes a name become three lines and get truncated.
iOS 16
In iOS 16, SwiftUI got new variation of lineLimit
modifier, lineLimit(_:reservesSpace:)
. This modifier does what we are trying to accomplish in this article.
What we need to do is remove our workaround ("\n") and repalce .lineLimit(2)
with .lineLimit(2, reservesSpace: true)
.
struct ProductCard: View {
let imageName: String
let name: String
let chef: String
let price: String
var body: some View {
VStack {
Image(imageName)
.resizable()
.scaledToFill()
.frame(width: 150, height: 150)
.clipShape(Circle())
.shadow(radius: 10)
VStack(alignment: .leading, spacing: 4) {
Text(name)
.lineLimit(2, reservesSpace: true)
.font(.title.bold())
Text("by \(chef)")
.bold()
.foregroundColor(.gray)
HStack {
Text("$\(price)")
.font(.headline.bold())
.padding(.top, 8)
}
}.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(20)
.frame(width: 250)
.background()
.cornerRadius(8)
.shadow(radius: 10)
}
}
You can read more about lineLimit improvements here.
You can easily support sarunw.com by checking out this sponsor.
Localization Buddy: Easiest way to localize and update App Store metadata.
Conclusion
This is a simple hack that I use many times when I want to force the same number of lines across various text size ranges. The pro of this hack is the speed, and the con isn't that bad either.
In a future article, I might come up with a more elegant solution. Stay tuned.
Beautiful soup and breakfast photos by Monika Grabkowska on Unsplash. ↩︎
Read more article about SwiftUI, Text, or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareHow to fix "Unable to boot the iOS simulator" error
There might be several reasons that cause this error. I will share the solution that works for me.
How to change the keyboard shortcut for IntelliSense in VS Code
I couldn't initiate IntelliSense for a long time because I couldn't find any Keyboard shortcuts for "IntelliSense". If you are in the same situation, I have a solution for you.