Swift View视图未对齐排查全过程
Swift View视图未对齐排查全过程

Swift View视图未对齐排查全过程

排查过程

在我的《汇率仓库》应用中出现内容未对齐的情况:

图片中的第一个视图为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,来解决该间距问题。

      如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

      发表回复

      您的电子邮箱地址不会被公开。 必填项已用 * 标注