看不见的幽灵:SwiftUI “隐形”视图调试一例

269 阅读4分钟

在这里插入图片描述

概述

时常与 SwiftUI 一起翩翩起舞的秃头小码农们一定都知道,其中内置平淡无奇的 Spacer 视图往往是我们把控界面布局的“妙手偶得”。

在这里插入图片描述

虽然大家都明白借助 Spacer 我们可以进一步调整视图的实际走位,但是用它的另一个构造器 init(minLength: CGFloat?) 创建的 Spacer 又有什么玄机呢?

在本篇博文中,您将学到如下内容:

  1. Spacer(minLength: 0) 到底有什么用?
  2. 渺无踪影:如何调试看不见的 Spacer?
  3. “黑洞理论”:SwiftUI 调试秘技!

相信本文的内容会让初学 SwiftUI 小伙伴们的调试技术更进一步!那还等什么呢?让我们马上开始"隐形幽灵"的调试之旅吧!

Let‘s find out!!!;)


1. Spacer(minLength: 0) 到底有什么用?

对于 SwiftUI 中不起眼的 Spacer 视图,一种非常行之有效的用途就是将容器中的其它视图“夹紧”,以让它们居中摆放:

HStack {
   Image(systemName: "pencil.tip.crop.circle")
        .font(.largeTitle.weight(.heavy))
        .foregroundStyle(.red)
    
    Spacer()
    
    Text("Hello Panda Hopy!")
    
    Spacer()
}

在上面的代码中,我们利用 Spacer 将 HStack 容器中 Text 视图居中显示,这里的居中实际上是相对头部 Image 视图尺寸的居中:

在这里插入图片描述

在 Apple 官方开发文档里对 Spacer 的描述也是非常简单,它就像一块可扩展的空间,能够根据不同容器的内部布局而自动展开:

在这里插入图片描述

不过,如果大家观赏过足够多 SwiftUI 的源代码就会发现,很多大牛都会使用 Spacer 的另外一种构造器 Spacer(minLength:) 来创建它,它和直接使用 Spacer() 创建的视图会有什么不同吗?

在这里插入图片描述

在下面的代码中,我们分别尝试了用两种 Spacer 构造器来影响 Text 视图的布局:

HStack {
    Image(systemName: "pencil.tip.crop.circle")
        .font(.largeTitle.weight(.heavy))
        .foregroundStyle(.red)
    
    Spacer()
    
    Text("Hello Panda Hopy!")
    
    Spacer()
}

HStack {
    
    Image(systemName: "pencil.tip.crop.circle")
        .font(.largeTitle.weight(.heavy))
        .foregroundStyle(.red)
    
    Spacer(minLength: 0)
    
    Text("Hello Panda Hopy!")
    
    Spacer(minLength: 0)
    
}

但是,运行的结果却没有任何差别,这是怎么回事呢?难道说 Spacer 这两种构造器的作用是一毛一样的?

在这里插入图片描述

2. 渺无踪影:如何调试看不见的 Spacer?

要想在 SwiftUI 里怡然自乐的调试界面布局,我们首先要搞清楚的就是界面中各个视图的大小和位置。一般这是通过主动在视图外围轮廓上绘制边界来达成的。

对于之前的代码,我们可以尝试为 Spacer 绘制边界来探查些许蛛丝马迹:

HStack {
    Image(systemName: "pencil.tip.crop.circle")
        .font(.largeTitle.weight(.heavy))
        .foregroundStyle(.red)
    
    Spacer(minLength: 0)
        .border(.red)
    
    Text("Hello Panda Hopy!")
    
    Spacer(minLength: 0)
        .border(.red)
}

不过遗憾的是,不像其它“正经”的 SwiftUI 视图,在 Spacer 绘制边界线将会徒劳无功,从界面上看不出哪怕一丁点儿差别:

在这里插入图片描述

由此看来,Spacer 就像一个不占据任何空间的“黑洞”,你永远无法直接观察到它。

那么,我们该如何拨云见日,剖析它的隐藏特性呢?

3. “黑洞理论”:SwiftUI 调试秘技!

我不知道小伙伴们是否听说过一种“黑洞”理论,它是关于如何在茫茫宇宙中找寻黑洞的方法。同样,你无法直接“看”到黑洞的存在,但是我们可以通过观察黑洞对其周边物质的影响来间接定位它。

受到“黑洞”理论的启发,我们将之前的代码做出如下修改:

HStack {
    Image(systemName: "pencil.tip.crop.circle")
        .font(.largeTitle.weight(.heavy))
        .foregroundStyle(.red)
        .border(.red)
    
    Spacer(minLength: 0)
    
    Text("Hello Panda Hopy!")
        .border(.red)
    
    Spacer(minLength: 0)
}

在上面的代码中,我们反其道而行之,不再去纠结 Spacer 的模样,而是直接在它周围的视图上做文章。运行可以看到,貌似还是“雾里看花”,不甚明了:

在这里插入图片描述

别急,让我们再主动增加一下 Image 的宽度,使一切真相大白:

Image(systemName: "pencil.tip.crop.circle")
    .font(.largeTitle.weight(.heavy))
    .foregroundStyle(.red)
    // 增加 Image 的宽度
    .frame(width: 150)
    .border(.red)

再次编译,在 Xcode 预览中一窥究竟:

在这里插入图片描述

从上图中可以清楚的看到,默认 Spacer() 构造器会让创建的 Spacer 产生一个微小的“间隙”,而 Spacer(minLength: 0) 则会将这个间隙彻底抹除。所以,在复杂 UI 布局中,利用后者我们可以更加充分的利用容器内部的空间,让 Spacer 看起来更加纯粹。

现在,大家知道为何要用 Spacer(minLength: 0) 构造器来创建“空白”了吧?棒棒哒!💯

总结

在本篇博文中,我们讨论了 SwiftUI 中 Spacer 的 init(minLength: CGFloat?) 构造器和默认的有什么不同,并借机向大家展示了 SwiftUI 界面中调试“隐形视图”的不二法门。

感谢观赏,再会啦!8-)