Reputation: 284
So this is a tough one. I have a dynamically generated sentence. Essentially, I have a view that is a dynamic image and on the left side of it, there's an overlaid 'darker area' with some text on top of it (title & subtitle). I'm running into a problem though. When there is an especially long word in 'title', the word gets cut off and wrapped around to the next line. This looks ugly and is confusing. What I'd like to do is scale the overall string so that the largest word fits into the dark area (with frame width of 60% the screen width) so that this ugly wrapping doesn't happen. At the same time, all this needs to fit into the max height I've defined.
I've tried working with solutions similar to the one described here: https://malauch.com/posts/auto-resizable-text-size-in-swiftui/ and this might work if I wrapped a ForEach in a VStack and walked through each word in the string. The only issue with this is the strings can be 10 words or so in some cases, which makes the title/subtitle not fit. Any suggestions are much appreciated, thanks!
ZStack(alignment: .top) {
Image(systemName: "camera")
.data(url: URL(string: URLOfAnImage)!)
.resizable()
.scaledToFill()
.maxHeight(260)
.frame(width: UIScreen.main.bounds.width)
.clipped()
HStack {
ZStack(alignment: .center) {
Color.black
.opacity(0.8)
VStack(alignment: .leading, spacing: 10) {
HStack {
Text(title.uppercased())
.font(.system(size: 26, weight: .bold))
.foregroundColor(Color.white)
Spacer()
}
Text(subtitle)
.font(.system(size: 17, weight: .bold))
.foregroundColor(Color.white)
}.padding(.leading, 25)
.padding(.trailing, 15)
}.frame(width: UIScreen.main.bounds.width * 0.6)
Spacer()
}
}.fixedSize(horizontal: false, vertical: true)
Should not look like: https://i.sstatic.net/NI1dy.png
Should look like: https://i.sstatic.net/TvRFB.png
So font size should scale based on the longest word, so the UI element looks cleaner overall and is more readable.
UPDATE: I've been playing around with the frame and minWidth, maxWidth, and idealWidth. Was hoping setting idealWidth of the ZStack to 60% of the screen width and then maxWidth to maybe 80%, but this just defaults to the 80% because the text element is wrapping...
Upvotes: 0
Views: 186
Reputation: 843
In your examples some words having spaces between and others dont. If they all have spaces in between then just use .multilinetextalignment and set the frame width for the text.
If you really want to scale by longest word try something like this:
let testString = "This is a test string for testing"
let longestWord = testString.components(separatedBy: " ").max { $1.count > $0.count }
//create a switch case that returns the size for the longest word
//display the text in a for each...
//add this to the text in for each
.font(isLongest ? .system(.size: 12) : .system(size: 22)
Hopefully this will give you the right idea
EDIT:
HStack {
ForEach(longestWord) { word in
Text(word)
.frame(width: isLongest ? 100 ? 10)
}
}
.frame(width: 100)
This should do what you want? Or try a similar method with .lineSpacing()
Upvotes: 0