SwiftUI 调整视图内容周围间隙(Content Margins)的“时髦”方法

概述

在 SwiftUI 开发的应用中,往往在小屏设备(比如 iPhone)上布局良好的 App 放到大屏(iPad)上后就会"一塌糊涂"。因为它们一味的只想着"占据"却不知道"舍弃"。

从 iOS 17.0(iPad 17.0)开始苹果提供了原生的视图修改器方法专注于处理此事。

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

  1. "不和谐"的 iPad 内容空白
  2. 使用屏幕类别(Size Class)因地制宜
  3. iOS 17 新增的视图间隙调整方法

相信学完本课后,小伙伴们无论在何种尺寸屏幕上的 App 都会运行的恰如其分、悠然自得。

那还等什么呢?Let's fix it!!!;)


1. "不和谐"的 iPad 内容空白

下面是一段非常简单的 SwiftUI 代码,我们在视图中显示了一个包含 100 行内容的列表:

swift 复制代码
struct ContentView: View {
    var body: some View {
        NavigationStack {
            List {
                ForEach(1..<100) { index in
                    Text("Item \(index)")
                }
            }
            .font(.title)
            .navigationTitle("Item list")
        }
    }
}

这在 iPhone 上表现的还算"中规中矩":

不过,如果在 iPad 上运行又会有怎样的结果呢?

可以看到:我们的 App 在大屏设备上并没有很好的把控"浩瀚无垠"的尺寸,它只是"单纯"的占据所有空间而已。

实际上,我们希望 App 在空间充足的情况下可以更加小巧紧凑,而不是一味"得寸进尺"的"索取"。

2. 使用屏幕类别(Size Class)因地制宜

在 SwiftUI 开发中,我们可以利用屏幕类别(Size Class)来检测当前运行设备屏幕的尺寸类型,然后根据需要因地制宜的调整对应的布局:

理想情况下我们可以在 iPhone 上保持布局不变,而在 iPad 上运行时"知趣的"为视图周边增加稍许横向空白:

swift 复制代码
struct ContentView: View {
    @Environment(\.horizontalSizeClass) private var sizeClass
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(1..<100) { index in
                    Text("Item \(index)")
                }
            }
            .font(.title)
            .navigationTitle("Item list")
            .safeAreaPadding(.horizontal, sizeClass == .regular ? 100 : 0)
        }
    }
}

运行代码,我们发现在 iPad 中 List 内容多了一些横向间隙,这样看起来显得更加安安合适啦!

不过用上面这种方法增加列表空白间隙的同时也会横向"压缩" List 滚动条的位置,这往往不是我们想要的结果。

别担心,我们可以轻而易举的搞定它!

3. iOS 17 新增的视图间隙调整方法

用 safeAreaPadding 修改器方法来增加横向间隙时会导致滚动条也参与到布局的"考量"之中。

有时,我们仅仅希望压缩视图内容而将滚动条的位置保持"原封不动"。幸运的是,从 iOS 17(iPad 17)开始苹果提供了全新的 contentMargins 修改器方法为我们分忧解难:

使用它我们可以非常方面的细粒度定制空白间隙的外观,比如我们可以选择间隙会影响哪些对象:

swift 复制代码
struct ContentView: View {
    @Environment(\.horizontalSizeClass) private var sizeClass
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(1..<100) { index in
                    Text("Item \(index)")
                }
            }
            .font(.title)
            .navigationTitle("Item list")
            .contentMargins(
                .horizontal,
                sizeClass == .regular ? 100 : 0,
                for: .scrollContent
            )
        }
    }
}

在上面的代码中,我们调用 contentMargins 方法并向其最后一个实参传入 .scrollContent 值,这表示我们对内容周边空间的"压缩"并不会影响滚动条的位置:

再次运行代码,现在 iPad 列表内容得到了完美的横向空白间隙,而且滚动条的位置仍然保持不变!棒棒哒!💯

总结

在本篇博文中,我们讨论了在 SwiftUI 中调整视图周边空白间隙从而让其在 iPhone 和 iPad 都表现得相当 nice 的方法,我们还进一步介绍了如何利用 iOS 17(iPad 17)里新增的方法让以上的实现更加锦上添花的"秘技"!

感谢观赏,再会!8-)

相关推荐
四眼蒙面侠12 小时前
深入 Open Agent SDK(番外篇):实战验证——把 SDK 塞进一个 macOS 原生 Agent 应用
swift·claudecode·bmad·agentsdk·openagentsdk
2501_915106321 天前
在Mac上搭建iOS开发环境的详细步骤与注意事项
ide·vscode·macos·ios·个人开发·swift·敏捷流程
harder3212 天前
RMP模式的创新突破
开发语言·学习·ios·swift·策略模式
sakiko_2 天前
UIKit学习笔记2-组件嵌套、滚动视图等
笔记·学习·objective-c·swift·uikit
四眼蒙面侠2 天前
深入 Open Agent SDK(五):会话持久化与安全防线
swift·claudecode·bmad·openagentsdk
ZZH_AI项目交付3 天前
扫脸功能交给 SDK 后,主工程里的旧代码怎么删除
ios·app·apple
茶底世界之下3 天前
诡异!String 参数在闭包里变成了 <uninitialized>,我排查了整整两天
ios·xcode·swift
四眼蒙面侠3 天前
深入 Open Agent SDK(四):多 Agent 协作——子代理、团队与任务编排
swift·agentsdk·openagentsdk
东坡肘子3 天前
Swift 并发正被更广泛地接纳 -- 肘子的 Swift 周报 #133
人工智能·swiftui·swift
四眼蒙面侠4 天前
深入 Open Agent SDK(三):MCP 集成实战——让 Agent 连接万物
swift·agentsdk·openagentsdk