实现需求
在SwiftUI视图中,上面是两组元素:
struct ContentView: View {
var body: some View {
HStack() { // 使用自定义对齐方式
VStack {
Text("WebSite")
Image(systemName: "globe")
.font(.system(size: 100))
}
VStack {
Text("https:")
Text("fangjunyu.com")
.font(.largeTitle)
}
}
}
}
在 SwiftUI 中,HStack 和 VStack 支持对齐选项,比如 .top、.bottom、.center 等。但是,当多个视图分布在不同容器(如 VStack 中)时,无法直接对齐它们的特定位置。此时,需要定义自定义的对齐方式。
在这一场景中,因为两组元素在同一个HStack中,但他们又在不同的VStack中。所以,如果想要 Text(“webSize”) 与 Text(“fangjunyu.com”) 对齐的话,就需要定义一个自定义的对齐方式,确保两个元素按照统一基准对齐。
自定义对齐方式
1、对齐方式和 AlignmentID 协议
SwiftUI 提供了一种机制来创建自定义的对齐方式:
VerticalAlignment:定义垂直方向上的对齐。
AlignmentID 协议:用于指定视图的对齐点。
通过扩展 VerticalAlignment 并遵守 AlignmentID 协议,可以创建一个自定义的对齐点。
2、定义自定义的垂直对齐
先创建一个自定义的对齐方式,命名为 midWebName。
import SwiftUI
// 扩展 VerticalAlignment,添加自定义对齐方式
extension VerticalAlignment {
// 定义一个结构体或枚举,用来标识对齐点
struct MidWebName: AlignmentID {
// 提供一个默认值(当视图未指定对齐点时使用)
static func defaultValue(in context: ViewDimensions) -> CGFloat {
context[.top] // 默认使用视图的顶部对齐
}
}
// 创建一个静态属性,用于方便引用
static let midWebName = VerticalAlignment(MidWebName.self)
}
代码解释:
1、扩展 VerticalAlignment
通过扩展 VerticalAlignment 来创建新的对齐方式。
2、定义 MidWebName 结构体
这个结构体遵守 AlignmentID 协议。
defaultValue 方法:用于提供默认的对齐点,这里设置为视图的顶部(context[.top])。
3、静态属性 midWebName
通过 VerticalAlignment 构造函数,将 MidWebName 类型作为参数,创建一个新的对齐方式。
3、使用自定义的对齐方式
现在,可以将 midWebName 用在布局中,确保两个不同容器中的元素对齐到一个统一的基准点。
import SwiftUI
struct ContentView: View {
var body: some View {
HStack(alignment: .midWebName) { // 使用自定义对齐方式
VStack {
Text("WebSite")
.alignmentGuide(.midWebName) { d in d[VerticalAlignment.center] }
Image(systemName: "globe")
.font(.system(size: 100))
}
VStack {
Text("https:")
Text("fangjunyu.com")
.alignmentGuide(.midWebName) { d in d[VerticalAlignment.center] }
.font(.largeTitle)
}
}
}
}
代码解析:
1、HStack(alignment: .midWebName)
将 HStack 的垂直对齐方式设置为自定义的 midWebName。
2、.alignmentGuide(.midWebName)
为需要对齐的视图(WebSite和 fangjunyu.com)指定一个对齐参考点。
使用 d[VerticalAlignment.center]:让视图的中心作为对齐点。
3、结果:
即使这两个文本在不同的 VStack 中,它们的中心也会按照 midWebName 这个自定义基准点对齐。
4、运行结果
视图将按照以下规则排列:
左侧的 WebSite 和右侧的 fangjunyu.com,它们的中心位置会垂直对齐。
即使在各自的 VStack 中增加其他内容,这两个元素仍然保持居中对齐。
总结
自定义对齐步骤:
1、扩展 VerticalAlignment。
2、定义一个遵守 AlignmentID 协议的结构体或枚举。
提供一个默认对齐点(如 context[.top])。
3、创建一个静态属性,方便引用。
4、在容器中设置自定义对齐方式,使用 .alignmentGuide() 设定视图的对齐基准。
参考文章
1、How to create a custom alignment guide:https://www.hackingwithswift.com/books/ios-swiftui/how-to-create-a-custom-alignment-guide
2、SwiftUI常用的对齐方式:https://fangjunyu.com/2024/12/17/swiftui%e5%b8%b8%e7%94%a8%e7%9a%84%e5%af%b9%e9%bd%90%e6%96%b9%e5%bc%8f/
扩展知识
VerticalAlignment 和 VStack 的关系
在 SwiftUI 中,VStack 用于垂直排列子视图,并且允许通过 alignment 参数设置视图的对齐方式。
VerticalAlignment 就是 SwiftUI 提供的一组垂直对齐选项,用来定义子视图在 VStack 中如何对齐。
VStack 的 alignment 参数:
用于指定所有子视图的对齐基准,例如 .leading、.center、.trailing。
VStack(alignment: .leading) {
Text("Hello")
Text("SwiftUI")
}
在上面的代码中,所有视图会向 leading(左侧)对齐。
VerticalAlignment:
是一个枚举,包含内置的垂直对齐选项,同时允许用户扩展自定义对齐方式。
内置的对齐方式:.top、.center、.bottom
自定义对齐方式:通过扩展 VerticalAlignment 创建新的对齐点。
AlignmentID 协议是什么?
AlignmentID 是 SwiftUI 中的一个协议,主要用于创建自定义对齐基准。通过实现 AlignmentID,可以定义新的对齐方式,并精确控制视图的对齐点。
AlignmentID 的要求:
必须提供一个 defaultValue 静态方法。
该方法返回一个 CGFloat,表示当视图没有明确的对齐点时,应该使用的默认值。
参数 ViewDimensions 提供了视图的布局信息,例如 .top、.bottom、.leading 等位置的值。
为什么需要 AlignmentID?
SwiftUI 内置的对齐方式(如 .top、.bottom)不能满足所有对齐需求,比如让两个不同 VStack 中的视图按一个特定基准点对齐。AlignmentID 可以自定义对齐点,实现更精细的控制。