SwiftUI 为我们提供了许多有价值的方法来控制视图的对齐方式,我将逐一介绍这些方法,以便您可以看到它们的实际操作。
- 最简单的对齐选项是使用
frame()
修饰符的alignment
参数。
请记住,文本视图总是使用显示其文本所需的精确宽度和高度,但是当我们在其周围放置边框时,它可以是任何大小。由于父对象对子对象的最终大小没有发言权,因此这样的代码将创建一个300x300的框架,并在其内部以较小的文本视图为中心:
Text("Live long and prosper")
.frame(width: 300, height: 300)
如果不希望文本居中,请使用frame()
的alignment
参数。例如,当在从左到右的环境中运行时,此代码将视图放在左上角
.frame(width: 300, height: 300, alignment: .topLeading)
然后可以使用offset(x:y:)
在 frame 内移动文本。
- 下一个选项是使用堆栈的对齐参数。
例如,这里有四个大小不同的文本视图排列在HStack
中:
HStack {
Text("Live")
.font(.caption)
Text("long")
Text("and")
.font(.title)
Text("prosper")
.font(.largeTitle)
}
我们没有指定对齐方式,因此默认情况下它们将居中。这看起来不太好,所以您可能会考虑将它们全部对齐到一个边,以获得更整洁的线条,如下所示:
HStack(alignment: .bottom) {
然而,这看起来也很糟糕:因为每个文本视图的大小不同,它们也有不同的基线——这就是“abcde”之类的字母在一行上的名称,这不包括行下方的字母,如“gjpy”。因此,小文本的底部低于较大文本的底部。
幸运的是,SwiftUI有两个特殊的对齐方式,可以在第一个子级或最后一个子级的基线上对齐文本。这将导致堆栈中的所有视图在一个统一基线上对齐,而不管它们的字体是什么:
HStack(alignment: .lastTextBaseline) {
接下来,为了实现更细粒度的控制,我们可以为每个单独的视图定制“对齐”的含义。为了更好地了解这是如何工作的,我们将从以下代码开始:
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)
}
}
运行时,您将看到VStack
紧紧围绕着两个文本视图,背景为红色。两个文本视图的长度不同,但由于我们使用了.leading
对齐方式,因此在从左到右的环境中,它们都将与它们的左边缘对齐。除此之外还有一个蓝色背景的大框架。因为frame大于VStack
,所以以VStack
中间为中心。
现在,当VStack
开始对齐这些文本视图时,它要求它们提供它们的 leading。默认情况下,这很明显:它使用视图的左边缘或右边缘,具体取决于系统语言。但是如果我们想改变这一点呢?如果我们想让一个视图具有自定义对齐方式呢?
SwiftUI为此提供了alignmentGuide()
修饰符。这需要两个参数:我们要更改的指南和返回新对齐方式的闭包。闭包被赋予一个ViewDimensions
对象,该对象包含其视图的宽度和高度,以及读取其各种边的能力。
默认情况下,视图的.leading
对齐向导是其.alignmentGuide(.leading)
——我知道这听起来很明显,但实际上它相当于:
VStack(alignment: .leading) {
Text("Hello, world!")
.alignmentGuide(.leading) { d in d[.leading] }
Text("This is a longer line of text")
}
我们可以重写该对齐向导,以使用视图的 trailing 作为其leading gaide 对齐向导,如下所示:
VStack(alignment: .leading) {
Text("Hello, world!")
.alignmentGuide(.leading) { d in d[.trailing] }
Text("This is a longer line of text")
}
现在您将看到我为什么要添加颜色:第一个文本视图将向左移动,以便它的右边缘位于下面视图的左边缘的正上方,
VStack
将展开以包含它,整个内容仍将位于蓝色框架的中心。
此结果与使用offset()
修饰符不同:如果偏移文本,则其原始尺寸实际上不会更改,即使生成的视图在不同的位置呈现。如果我们偏移了第一个文本视图而不是改变它的对齐指南,VStack
不会扩展到包含它。
虽然对齐导向闭包已传递给视图的尺寸,但如果不想使用,则不需要使用它们–可以发回硬编码的编号,或创建其他计算。例如,通过将10个文本视图的位置乘以-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)
}
要完全控制对齐指南,您需要创建自定义对齐指南。我认为这本书应该有一个小章节…
Alignment and alignment guides