排查过程
在我的《汇率仓库》应用中出现内容未对齐的情况:
图片中的第一个视图为HomeView,第二个视图为WarehouseView文件。
可以发现,红色的代码部分是对齐的,绿色的汇率内容部分没有对齐,相比之前“仓库”视图的汇率内容更低一些,我将通过代码分析来排查汇率内容未对齐的具体原因。
HomeView代码部分:
struct HomeView: View {
var body: some View {
...
// 汇率列表部分,上面都是对齐的,不用管
// Button按钮部分高度为 90
Button(action: {
...
}
.padding()
.frame(height: 90)
// 汇率内容部分,后面都是一致的
}
}
WarehouseView视图代码:
struct WarehouseView: View {
var body: some View {
...
// 汇率列表部分,上面都是对齐的,不用管
// 储备金额题目
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 50)
VStack(alignment: .leading) {
// 储备金额
HStack {
VStack{
...
}
Spacer().frame(width: 10)
Text("14,333,2222")
.padding(.horizontal,10)
.padding(.vertical,10)
}
}
.padding()
.frame(height: 40)
// 汇率内容部分,后面都是一致的
}
}
我将这两个视图中间不会影响高度的代码都隐藏了,以便评判影响对齐高度的原因。在上面的两组代码中,HomeView视图是一个按钮区域,这个frame高度为90,在WarehouseView视图中是两个Stack结构,这两个结构的高度分别为50和40。
因此两个View视图的按钮和Stack结构部分,如果仅对比Frame的高度,那么都会是90,View视图中应该是对齐的。但问题是WarehouseView视图的汇率内容部分更矮,导致切换视图查看时,会发现该问题,并且明显会影响到预览效果。
因为HomView视图只有一个高度为90的按钮,因此,我通过“对比大法”(可用于数据库、代码等多种途径,多重对比寻找原因),将WarehouseView的两个文字区域改为一个文字区域展示两遍,每个重复的文字区域都设置高度为45。
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 50)
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
一个高度为90,另外两个内容一样高度为45,这样可以发现具体是哪个文字区域的问题:
通过对比发现,两个文字内容区域占比都会比按钮区域要大。因此,这两个文字区域占比大存在共性。
当我尝试将单个文字区域设置为90高度,与按钮一致后:
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 90)
发现汇率右侧文字内容高度重合:
由此可以做出简单的判断,那就是当存在两个Stack时,布局的高度就会略微增加,可能是padding或者类似HTML的margin边距问题导致的,但Xcode又没有办法去校验高度。
当我尝试给标题的两个文字区域添加红色背景色时,发现两个区域之间是存在空隙的,应该就是这个空隙导致显示的汇率信息存在偏移。
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 45)
.padding(.vertical, 0)
.background(Color.red)
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 45)
.background(Color.red)
我在尝试的过程中,给两个文本区域添加padding为0的属性,但是仍然没有奏效。
问题原因
经过一系列排查,经过发现两个文本区域之间的空白区域,是由视图的默认间距引起的。
SwiftUI在某些布局中会自动添加一些空白区域,即使没有显示设置padding,以下一些方法来调整和消除这些间距:
1、使用spacing参数:
如果两个 HStack 是嵌套在一个 VStack 中,SwiftUI 默认会在 VStack 的元素之间添加间距。我们可以通过设置 spacing 为 0 来消除这些间距:
VStack(spacing: 0) {
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 45)
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 45)
}
2、使用.fixedSize():
.fixedSize(horizontal: false, vertical: true) 可以防止视图被拉伸到多余的空间。它的用法很简单,通过指定 horizontal 和 vertical 参数,可以控制视图在水平和垂直方向上是否固定大小。
尝试在 HStack 上应用 .fixedSize(horizontal: false, vertical: true),这样可以确保每个 HStack 只占用它们的内容高度,避免因为其他布局规则而被拉伸。
VStack(spacing: 0) {
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 45)
.fixedSize(horizontal: false, vertical: true) // 防止垂直方向拉伸
HStack {
Text(String(localized: "Reserve amount"))
.font(.system(size: 24))
Spacer()
}
.frame(height: 45)
.fixedSize(horizontal: false, vertical: true) // 防止垂直方向拉伸
}
horizontal: false:允许视图在水平方向上调整大小,不强制为内容大小。
vertical: true:在垂直方向上视图固定为内容的高度,避免因为布局约束拉伸高度。
这样可以确保 HStack 不会因为布局机制而占据额外的高度空间.
总结
我没有尝试.fixedSize()的解决方案,而是采取给最外层的VStack添加spacing:0。
struct WarehouseView: View {
var body: some View {
NavigationStack {
VStack(spacing: 0) {
...
}
}
}
}
当我给最外层的VStack添加spacing:0之后,发现原本的红色区域之间的空白消失了(没有再复现,所以没截图),同时发现其他区域的间距也缩小了(也忘记截图了)。
经过一些间距的调整后,展示出了最完美的内容布局,所以的内容高度都对应了,包括本次的右侧汇率信息的部分。
因此,Swift在每个VStack、HStack等等区域之间,都会默认插入一个间距,而且这个间距无法通过padding()调整。
最终的解决方案就是给外层的VStack或HStack或其他组件添加一个spacing:0,来解决该间距问题。