Swift Continue a Line on Next Line

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.

Example of product card views with different heights based on the product name length.
Example of product card views with different heights based on the product name length.

Today, I'm going to show you a quick and dirty hack to set a minimum text line for a text view. [1]

Sponsor sarunw.com and reach thousands of iOS developers.

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.

Force product name to take two lines.
Force product name to take two lines.

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 )

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.

If your product name takes two lines, it will render in truncated form.
If your product name takes two lines, it will render in truncated form.

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.

Sponsor sarunw.com and reach thousands of iOS developers.

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.


  1. Beautiful soup and breakfast photos by Monika Grabkowska on Unsplash. ↩︎

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.

logandisper1982.blogspot.com

Source: https://sarunw.com/posts/how-to-force-two-lines-of-text-in-swiftui/

0 Response to "Swift Continue a Line on Next Line"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel