通过使用高度作为默认对齐方式,它创造了一种有趣的效果:

struct CustomView: View {
var body: some View {
VStack(alignment: .weirdAlignment, spacing: 10) {
Rectangle()
.fill(Color.primary)
.frame(width: 1)
.alignmentGuide(.weirdAlignment, computeValue: { d in d[.leading] })
ColorLabel(label: "Monday", color: .red, height: 50)
ColorLabel(label: "Tuesday", color: .orange, height: 70)
ColorLabel(label: "Wednesday", color: .yellow, height: 90)
ColorLabel(label: "Thursday", color: .green, height: 40)
ColorLabel(label: "Friday", color: .blue, height: 70)
ColorLabel(label: "Saturday", color: .purple, height: 40)
ColorLabel(label: "Sunday", color: .pink, height: 40)
Rectangle()
.fill(Color.primary)
.frame(width: 1)
.alignmentGuide(.weirdAlignment, computeValue: { d in d[.leading] })
}
}
}
struct ColorLabel: View {
let label: String
let color: Color
let height: CGFloat
var body: some View {
Text(label).font(.title).foregroundColor(.primary).frame(height: height).padding(.horizontal, 20)
.background(RoundedRectangle(cornerRadius: 8).fill(color))
}
}
十、Aligning Non-Siblings
- 在前面的示例中,已经看到了如何创建自定义对齐,但这有什么意义呢?没有自定义对齐也可以实现相同的结果,使用自定义对齐的真正好处是,使用它们来对齐位于视图层次结构不同分支上的视图。
- 来看下一个例子:

- 如果分析这个视图的组件,将意识到我们需要将图像与文本视图对齐,但它们不属于同一个容器:

- 图像和文本视图都有一个共同的容器(HStack),因此将创建一个自定义对齐,以匹配它们的中心点。重要的是要记住适当地设置公共容器的对齐参数。
extension VerticalAlignment {
private enum MyAlignment : AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[.bottom]
}
}
static let myAlignment = VerticalAlignment(MyAlignment.self)
}
struct CustomView: View {
@State private var selectedIdx = 1
let days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
var body: some View {
HStack(alignment: .myAlignment) {
Image(systemName: "arrow.right.circle.fill")
.alignmentGuide(.myAlignment, computeValue: { d in d[VerticalAlignment.center] })
.foregroundColor(.green)
VStack(alignment: .leading) {
ForEach(days.indices, id: \.self) { idx in
Group {
if idx == self.selectedIdx {
Text(self.days[idx])
.transition(AnyTransition.identity)
.alignmentGuide(.myAlignment, computeValue: { d in d[VerticalAlignment.center] })
} else {
Text(self.days[idx])
.transition(AnyTransition.identity)
.onTapGesture {
withAnimation {
self.selectedIdx = idx
}
}
}
}
}
}
}
.padding(20)
.font(.largeTitle)
}
}
- 您可能想知道,所有没有明确指定垂直对齐的文本视图怎么办?它们不打算用隐式值吗?如果是这样,它们不都是一个叠在另一个上面吗?都是有效的问题。这是对齐指南的另一个令人困惑的事实。然而,在这种情况下,我们处理的是 VStack,而不是 ZStack,这意味着它里面的所有视图都必须垂直堆叠。Alignment guides 不会破坏这一点,布局系统将使用所选视图中的显式对齐来对齐箭头图像,其他没有明确指南的文本视图将相对于有明确指南的文本视图进行定位。
十一、ZStack 自定义对齐 Alignment
- 如果需要为 ZStack 创建自定义对齐,这里有一个模板:
extension VerticalAlignment {
private enum MyVerticalAlignment : AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[.bottom]
}
}
static let myVerticalAlignment = VerticalAlignment(MyVerticalAlignment.self)
}
extension HorizontalAlignment {
private enum MyHorizontalAlignment : AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[.leading]
}
}
static let myHorizontalAlignment = HorizontalAlignment(MyHorizontalAlignment.self)
}
extension Alignment {
static let myAlignment = Alignment(horizontal: .myHorizontalAlignment, vertical: .myVerticalAlignment)
}
struct CustomView: View {
var body: some View {
ZStack(alignment: .myAlignment) {
...
}
}
}
十二、总结
- 至此为止,已经看到了 alignment guides 是多么强大,一旦了解了它们能提供什么,它们就会变得更有意义。为了获得更好的体验,应该记住以下几点:
-
- 容器中的每个视图都有 alignment guides,如果未显式指定,则由容器的对齐参数确定;
-
- 在布局期间,与容器对齐参数中指定的类型不同的 alignment guides 将被忽略。
-
- VStack 使用水平对齐,而 HStacks 使用垂直对齐;
-
- 如果容器是紧密的,则 frame 方法中的对齐参数将没有视觉效果;
-
- 当来自视图层次结构不同分支的两个视图需要彼此对齐时,需要自定义 alignment guides。
- 本文中的大多数示例使用水平对齐,但是相同的概念也适用于垂直对齐。