SwiftUI 提供了视图不同边缘的对齐指南(.leading、trailing、top 等)以及 .center 和两个基线选项来帮助文本对齐。然而,当处理在不同视图之间分割的视图时,如果必须使在用户界面完全不同的两个视图部分对齐,这些方法都不能很好地很好解决问题。 为了解决类似的问题,SwiftUI 允许创建自定义的对齐辅助线,并在整个 UI 的视图中使用这些辅助线,在这些视图之前或之后发生什么并不重要,但它们仍然会排成一条线。 例如,下面的布局在左侧显示我的 CSDN 帐户名和我的个人资料头像,右侧显示 “CSDN ID:” 加上 “Forever_wj” 的大号字体:
struct ContentView : View {
var body: some View {
HStack {
VStack {
Text ( "@CSDN" )
Image ( "forever_wj" )
. resizable ( )
. frame ( width: 60 , height: 60 )
}
VStack {
Text ( "CSDN ID:" )
Text ( "Forever_wj" )
. font ( . title)
}
}
}
}
如果想让 “@CSDN” 和 “Forever_wj” 垂直对齐,那么现在就很难了。水平堆栈内部包含两个垂直堆栈,因此没有内置的方法来获得所需的对齐方式,像 HStack(alignment: .top) 这样的方便的方式。要解决这个问题,我们需要定义一个自定义布局指南,这应该是 VerticalAlignment 或 HorizontalAlignment 的扩展,并且是符合 AlignmentID 协议的自定义类型。 当说到“自定义类型”时,你可能会想到一个结构体,但实际上,我认为将其作为枚举来实现是一个更好的主意。AlignmentID 协议只有一个要求,即一致性类型必须提供一个静态 defaultValue(in:) 方法,该方法接受 ViewDimensions 对象并返回一个 CGFloat,指定“如果视图没有 alignmentGuide() 修饰符,该视图应该如何对齐“,将获得视图的现有 ViewDimensions 对象,因此可以选择其中一个作为默认值,也可以使用硬编码值。 具体实现如下所示:
extension VerticalAlignment {
struct MidAccountAndName : AlignmentID {
static func defaultValue ( in d: ViewDimensions ) - > CGFloat {
d[ . top]
}
}
static let midAccountAndName = VerticalAlignment ( MidAccountAndName . self )
}
可以看到,在默认情况下使用了 .top 视图维度,并且还创建了一个名为 midAccountAndName 的静态常量,以使自定义对齐更易于使用。 现在来分析一下为什么使用枚举比使用结构体更可取,原因如下:
刚刚创建了一个名为 MidAccountAndName 的新结构体,这意味着可以(如果需要的话)创建该结构体的实例,即使这样做没有任何意义,因为它没有任何功能;
如果将 struct MidAccountAndName 替换为 enum MidAccountAndName,那么就不能再创建它的一个实例了,它的存在只是为了容纳一些功能。 无论选择的是枚举还是结构体,其用法都保持不变:将其设置为堆栈的对齐方式,然后使用 alignmentGuide() 在要对齐的任何视图上激活它。这只是一个指南:它帮助我们沿一条直线对齐视图,但没有说明如何对齐视图,这意味着仍然需要为 alignmentGuide() 提供闭包,该闭包可以根据需要定位视图。 例如,可以将 CSDN 代码更新为 use.midAccountAndName,然后告诉帐户和名称使用其中心位置作为指南,明确地说,这意味着“对齐这两个视图,使它们的中心都位于 .midAccountAndName 指南上”:
struct ContentView : View {
var body: some View {
HStack ( alignment: . midAccountAndName) {
VStack {
Text ( "@CSDN" )
. alignmentGuide ( . midAccountAndName) { d in d[ VerticalAlignment . center] }
Image ( "forever_wj" )
. resizable ( )
. frame ( width: 60 , height: 60 )
}
VStack {
Text ( "CSDN ID:" )
Text ( "Forever_wj" )
. alignmentGuide ( . midAccountAndName) { d in d[ VerticalAlignment . center] }
. font ( . title)
}
}
}
}
这将确保它们是垂直对齐的,不管前面或后面是什么,只要有了这个示例,那么在前后添加更多的文本视图,SwiftUI 将重新定位所有内容,以确保对齐的两个视图保持不变。