SwiftUI 为我们提供了许多宝贵的方法来控制视图的对齐方式
最简单的对齐选项是frame修饰器的alignment参数。请记住,文本视图始终使用显示其文本所需的确切宽度和高度,但当我们在其周围放置一个可以具有任何大小的框架时。由于父级在子级的最终大小中没有发言权,因此这样的代码将创建一个 300x300 帧,其中以较小的文本视图为中心
struct sj_frame: View {
var body: some View {
Text("Live long and prosper")
.border(Color.orange)
.frame(width: 300, height: 300)
.border(Color.black)
}
}
image.png
如果您不希望文本居中,请使用frame()的alignment参数。例如,此代码在从左到右的环境中运行时将视图放置在左上角
.frame(width: 300, height: 300, alignment: .topLeading)
image.png
我们尚未在此处指定路线,因此默认情况下它们将居中。看起来不太好,所以您可能会考虑将它们全部对齐到一条边缘以获得更整齐的线条,如下所示
struct sj_frame_alignment: View {
var body: some View {
HStack {
// HStack(alignment: .bottom) {
Text("Live")
.font(.caption)
Text("long")
Text("and")
.font(.title)
Text("prosper")
.font(.largeTitle)
}
}
}
image.png
struct sj_frame_alignment: View {
var body: some View {
// HStack {
HStack(alignment: .bottom) {
Text("Live")
.font(.caption)
Text("long")
Text("and")
.font(.title)
Text("prosper")
.font(.largeTitle)
}
}
}
image.png
但是,这看起来也很糟糕:因为每个文本视图的大小都不同,所以它们的基线也不同–这就是“ abcde”之类的字母在一行上的名称,不包括该行下方的字母作为“ gjpy”。结果,小文本的底部比大文本的底部低。
幸运的是,SwiftUI具有两个特殊的对齐方式,它们使第一个孩子或最后一个孩子的基线上的文本对齐。这将导致堆栈中的所有视图在一个统一的基准上对齐,无论其字体如何:
HStack(alignment: .lastTextBaseline) {
image.png
继续,为了获得更细粒度的控制,我们可以自定义“对齐”对每个单独视图的含义。为了真正了解其工作原理,我们将从以下代码开始:
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
Text("Hello, world!")
Text("This is a longer line of text")
}
.background(Color.red)
.frame(width: 400, height: 400)
.background(Color.blue)
}
}
image.png
运行该命令后,您会看到VStack紧紧围绕着两个带有红色背景的文本视图。两种文本视图的长度不同,但是由于我们使用了.lead对齐,因此它们在左右环境中都将对齐到其左边缘。除此之外,还有一个更大的框架,背景为蓝色。因为框架比VStack大,所以VStack位于中间。
现在,当VStack对齐所有这些文本视图时,它要求它们提供leading edge。默认情况下这很明显:根据系统语言,它使用视图的左边缘或右边缘。但是,如果我们要更改它,怎么办–如果我们要使一个视图具有自定义对齐方式,该怎么办?
为此,SwiftUI为我们提供了alignmentGuide()修饰符。这有两个参数:我们要更改的指南,以及一个返回新对齐方式的闭包。给闭包提供了一个ViewDimensions对象,该对象包含其视图的宽度和高度,以及读取其各种边缘的功能。
默认情况下,视图的.leader对齐指南是其leading
的对齐指南–我知道这很明显,但实际上等效于此:
VStack(alignment: .leading) {
Text("Hello, world!")
.alignmentGuide(.leading) { d in d[.leading] }
Text("This is a longer line of text")
}
image.png
我们可以重写该对齐指南,以将视图的trailing用作其前导对齐指南,如下所示:
VStack(alignment: .leading) {
Text("Hello, world!")
.alignmentGuide(.leading) { d in d[.trailing] }
Text("This is a longer line of text")
}
image.png
现在,您将看到为什么我要添加颜色:第一个文本视图将移至左侧,以便其右侧边缘位于下面视图的左侧边缘的正上方,VStack将展开以包含它,并且整个过程仍然在蓝框内居中。
此结果与使用offset()修饰符不同:如果偏移文本,则即使原始视图在不同位置呈现,其原始尺寸也不会实际改变。如果我们偏移了第一个文本视图而不是更改其对齐方式,则VStack不会扩展为包含它。
尽管AlignmentGuide是通过视图的尺寸传递的,但如果不需要,则不需要使用它们。您可以发送回硬编码的数字,或进行其他计算。例如,这通过将其位置乘以-10来为10个文本视图创建分层效果
var body: some View {
VStack(alignment: .leading) {
ForEach(0..<10) { position in
Text("Number \(position)")
.alignmentGuide(.leading) { _ in CGFloat(position) * -10 }
}
}
.background(Color.red)
.frame(width: 400, height: 400)
.background(Color.blue)
}
image.png