For a dynamic layout reacting to width changes using ViewThatFits, I need a 2-line Text view where content gets wrapped exactly once, but doesn't get abbreviated. If the text is too long to fit in two lines, ViewThatFits should choose the next layout.
I tried to use .lineLimit(2, reservesSpace: true), but then ViewThatFits always takes this layout even when the text content gets too long to fit, so it gets abbreviated with "...", instead of choosing the next layout.
How else can I build a layout with a two-line Text, which does signal to ViewThatFits if the space doesn't fit the entire text so it can choose the next layout?
I have something that works though it's not ideal from a performance perspective; so definitely worth filing a follow up feedback as a request to simplify this and make it cheaper:
struct ContentView: View {
var content: String {
"This is some text which we hope will fit on two lines"
}
var body: some View {
// Reserve two lines (always)
Text(content)
.hidden()
.lineLimit(2, reservesSpace: true)
.accessibilityHidden(true)
.overlay {
ViewThatFits(in: .vertical) {
ZStack {
// Measurer: reports the full unwrapped height at the proposed width.
// Drives the fit check; never visible.
Text(content)
.fixedSize(horizontal: false, vertical: true)
.hidden()
.accessibilityHidden(true)
// Renderer: the actual 2-line layout.
Text(content)
.lineLimit(2, reservesSpace: true)
}
Text("Backup")
.lineLimit(2, reservesSpace: true)
}
}
}
}
Note: It is possible you don't need the outer hidden Text if there's other things to constrain your view but this was an easy way to set of a small sample app that shows the behavior.