Reputation: 5666
I have a custom chart with some texts as seen below. It aligns the first text correctly, it aligns the last text incorrectly. I need the VStack with the texts to stretch like an accordion so that the last text's centerY aligns with the bottom of the chart.
As seen with the blue Xcode highlight, the VStack receives the same size as the chart with an offset.
To align the first text, I extended VerticalAlignment as seen in WWDC 2019 - Session 237.
extension VerticalAlignment {
private enum TopChartAndMidTitle: AlignmentID {
static func defaultValue(in dimensions: ViewDimensions) -> Length {
return dimensions[.top]
}
}
static let topChartAndMidTitle = VerticalAlignment(TopChartAndMidTitle.self)
}
Then I used it like this:
var labels = ["1900", "1800", "1700", "1600", "1500", "1400"]
var body: some View {
HStack(alignment: .topChartAndMidTitle) {
chart()
.alignmentGuide(.topChartAndMidTitle) { $0[.top] }
valueLabels()
}
}
private func valueLabels() -> AnyView {
AnyView(VStack {
Text(labels[0]).font(.footnote)
.alignmentGuide(.topChartAndMidTitle) { $0[.bottom] / 2 }
ForEach(labels.dropFirst().identified(by: \.self)) { label in
Spacer()
Text(label).font(.footnote)
}
})
}
Question: How do I align the last text against the chart bottom and thereby stretch the VStack?
To test this, just replace my custom chart with Rectangle().fill(Color.red)
. It will result in the same problem.
Upvotes: 1
Views: 2122
Reputation: 257711
Today I would do it with the following approach...
Result demo
Code (TopChartAndMidTitle
used from original question "as is")
struct TestAlignScales: View {
var labels = ["1900", "1800", "1700", "1600", "1500", "1400"]
@State private var graphHeight = CGFloat.zero
var body: some View {
HStack(alignment: .topChartAndMidTitle) {
Rectangle().fill(Color.red)
.alignmentGuide(.topChartAndMidTitle) { d in
if self.graphHeight != d.height {
self.graphHeight = d.height
}
return d[.top]
}
valueLabels()
}
}
@State private var delta = CGFloat.zero
private func valueLabels() -> some View {
VStack {
ForEach(labels, id: \.self) { label in
VStack {
if label == self.labels.first! {
Text(label).font(.footnote)
.alignmentGuide(.topChartAndMidTitle) { d in
if self.delta != d.height {
self.delta = d.height
}
return d[VerticalAlignment.center]
}
} else {
Text(label).font(.footnote)
}
if label != self.labels.last! {
Spacer()
}
}
}
}
.frame(height: graphHeight + delta)
}
}
struct TestAlignScales_Previews: PreviewProvider {
static var previews: some View {
TestAlignScales()
.frame(height: 400)
}
}
Upvotes: 1