I am setting up the frame width and wondering if it is possible to have this display as a VStack
value:
title
instead of the default of a HStack when someone increases to a larger font size.
value: title
struct TextRowView: View {
let title: String
let value: String
let width: CGFloat
var body: some View {
LabeledContent {
Text(value)
.frame(width: width, alignment: .leading)
} label: {
Text(title)
.bold()
}
}
}
I'd write a custom LabeledContentStyle
.
If you just want to use a HStack
when a VStack
"doesn't fit", you can use ViewThatFits
:
struct DynamicStackStyle: LabeledContentStyle {
func makeBody(configuration: Configuration) -> some View {
ViewThatFits(in: .horizontal) {
HStack {
configuration.label
configuration.content
}
VStack {
configuration.label
configuration.content
}
}
}
}
extension LabeledContentStyle where Self == DynamicStackStyle {
static var dynamicStack: DynamicStackStyle { .init() }
}
LabeledContent {
...
} label: {
...
}
.labeledContentStyle(.dynamicStack)
If you want to specifically check for dynamic type size (I'm assuming that's what you mean by "increases to a larger font size"), you can do that too.
struct DynamicStackStyle: LabeledContentStyle {
@Environment(\.dynamicTypeSize) var size
func makeBody(configuration: Configuration) -> some View {
if size < .xLarge {
HStack {
configuration.label
configuration.content
}
} else {
VStack {
configuration.label
configuration.content
}
}
}
}
Note that the default labeled content style appears differently in list rows and other things. You cannot recreate this behaviour with your own labeled content style. If the default behaviour is desirable, you should not use a custom labeled content style. Just wrap the LabeledContent
directly with a ViewThatFits
or if size < .xLarge { ... } else { ... }
.
ViewThatFits(in: .horizontal) {
LabeledContent {
Text(value)
.frame(width: width, alignment: .leading)
} label: {
Text(title)
.bold()
}
VStack {
Text(value)
.frame(width: width, alignment: .leading)
Text(title)
.bold()
}
}