SwiftUI 让视图自适应高度的 6 种方法(一)

在这里插入图片描述

概览

在 SwiftUI 的世界里,我们无数次都梦想着视图可以自动根据布局上下文“因势而变”‌。大多数情况下,SwiftUI 会将每个视图尺寸处理的井井有条,不过在某些时候我们还是得亲力亲为。

在这里插入图片描述

如上图所示,无论顶部 TabView 容器里子视图高度如何变化,TabView 本身的高度都能“随遇而安”。如何用最简单、最现代化、最有趣且最切中要害的方法让容器尺寸与子视图的高度“如影随形”呢?

相信学完本课后,小伙伴们必能脑洞大开、格局打开,用“千姿百态”的方法让问题的解决一发入魂、九转功成!

那还等什么呢?Let‘s go!!!😉


1. 为什么要让视图高度自适应?

对于一个具体的示例来说,设想这样一种场景:每个 SwiftUI 子视图都包含了长度不定的文本,如何稳妥而优雅的据此设定它们父容器的高度呢?

在下面的代码中,我们的父容器 TabView 包含了若干个 likeIdiomCard 视图,每个 likeIdiomCard 视图对应一条自己喜爱的成语,其中每条成语又含有不固定长度的文本来表示自身的释义:

TabView {    
    ForEach(likeIdioms.chunked(into: 2), id: \.self) { idiomChunk in
        HStack {
            ForEach(idiomChunk) { idiom in
                likeIdiomCard(idiom)
            }
            
            if idiomChunk.count == 1 {
                Rectangle()
                    .foregroundStyle(.clear)
            }
        }
        
    }
}
.tabViewStyle(.page)
.frame(height: 200)

在这里插入图片描述

注意,为了简便起见我们将整个 TabView 的高度设置为了 200。不过,这样做的缺点也显而易见:

  • 当成语释义太短时,固定高度造成空间浪费;
  • 当成语释义太长时,固定高度又会造成空间不足;

如下图所示,左侧的成语释义很短,会导致底部残留过多空间,而右侧释义很长的成语会迫使 likeIdiomCard 在有限的空间里居中显示,造成顶部成语名称显示不全。

在这里插入图片描述

在这个接地气的例子中,如果 TabView 的高度可以根据每个 likeIdiomCard 视图的高度自动调整那就天衣无缝了。

当然,我们完全可以用自定义布局(Layout)来让挑战大功告成,可是这颇有些“导弹打蚊子”的感觉。不过为了确保整个讨论的完整性,我们仍然会在本系列最后一篇文章介绍如何用自定义布局完成 SwiftUI 视图高度自适应的第 6 种实现。

下面,就让我们先选出 5 种稍显“轻量级”的方法来让问题迎刃而解吧。

2. 初始工作

首先,为了保存所有 likeIdiomCard 子视图的最大高度,我们需要在主视图中创建一个 maxHeight 状态:

@State private var maxHeight = 0.0

我们的基本思路是,依次获取每个 likeIdiomCard 视图的高度,并始终将最大的那个保存到 maxHeight 里。

最后,我们只需设置 TabView 的高度为 maxHeight 即可:

TabView {    
    //...
}
.tabViewStyle(.page)
.frame(height: maxHeight)

3. 最古老的方法:GeometryReader

早在 SwiftUI(iOS 13)诞生那天,GeometryReader 视图就作为一个重要成员与之携手并肩了。

在这里插入图片描述

如果我没记错,GeometryReader 至今已经快 6 年了。虽然有许多不足之处,但它们并不影响我们使用 GeometryReader 来得偿所愿:

likeIdiomCard(idiom)
    .background {
        GeometryReader { proxy in
            if proxy.size.height > maxHeight {
                maxHeight = proxy.size.height
            }
            
            return Color.clear
        }
    }

在上面的代码中,我们机智的将 GeometryReader 作为 likeIdiomCard 的背景,这样做避免了它们的尺寸“各持己见”。利用 @ViewBuilder 语法的强大威力,我们将 maxHeight 状态的设置逻辑与返回“占位”视图完美的“融为一体”。


更多关于 GeometryReader 使用缺陷的介绍,请小伙伴们移步如下链接观赏精彩的内容:


想要进一步系统地学习 Swift 开发的小伙伴们,可以来我的《Swift 语言开发精讲》专栏逛一逛哦:

在这里插入图片描述


在下篇博文中,我们将继续 SwiftUI 视图尺寸适配之旅,介绍更多有趣的方法,不见不散!

总结

在本篇博文中,我们介绍了为何要让 SwiftUI 容器与子视图的尺寸“唇齿相依”,并讨论了一种“最古老”的解决之道。

感谢观赏,我们下篇见!😎

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大熊猫侯佩

赏点钱让我买杯可乐好吗 ;)

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值