View in English

  • Apple 开发者
    • 入门汇总

    探索“入门汇总”

    • 概览
    • 学习
    • Apple Developer Program

    及时了解最新动态

    • 最新动态
    • 开发者你好
    • 平台

    探索“平台”

    • Apple 平台
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    • App Store

    精选

    • 设计
    • 分发
    • 游戏
    • 配件
    • 网页
    • Home
    • CarPlay 车载
    • 技术

    探索“技术”

    • 概览
    • Xcode
    • Swift
    • SwiftUI

    精选

    • 辅助功能
    • AI 与机器学习
    • App Intents
    • Apple 智能
    • 游戏
    • 安全性
    • Xcode Cloud
    • 社区

    探索“社区”

    • 概览
    • “与 Apple 会面交流”活动
    • 社区活动
    • 开发者论坛
    • 开源

    精选

    • WWDC
    • Swift Student Challenge
    • 开发者故事
    • App Store 大奖
    • Apple 设计大奖
    • Apple Developer Centers
    • 文档

    探索“文档”

    • 文档库
    • 技术概述
    • 示例代码
    • 《人机界面指南》
    • 视频

    发布说明

    • 精选更新
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • Apple tvOS
    • Xcode
    • 下载

    探索“下载”

    • 所有下载
    • 操作系统
    • 应用程序
    • 设计资源

    精选

    • Xcode
    • TestFlight
    • 字体
    • SF Symbols
    • Icon Composer
    • 支持

    探索“支持”

    • 概览
    • 帮助指南
    • 开发者论坛
    • “反馈助理”
    • 联系我们

    精选

    • 《开发者账户帮助》
    • 《App 审核指南》
    • 《App Store Connect 帮助》
    • 即将实行的要求
    • 协议和准则
    • 系统状态
  • 快速链接

    • 活动
    • 新闻
    • 论坛
    • 示例代码
    • 视频
 

视频

打开菜单 关闭菜单
  • 专题
  • 所有视频
  • 关于
  • 简介
  • 转写文稿
  • SwiftUI 布局指南

    探索 SwiftUI 中布局的核心概念。了解如何构建灵活、动态的视图,使其与系统无缝协作,并探索重要的调试技巧来简化你的工作流程。

    这个讲座最初作为“与 Apple 会面交流”活动“SwiftUI 基础知识:使用 SwiftUI 构建卓越的 App”的一部分讲授。请观看完整视频,以了解更多见解和相关讲座。

    资源

      • 高清视频
      • 标清视频
  • 搜索此视频…

    大家早上好。大家好。 我叫凯特,是 Apple 公司的一名开发工具工程师。

    过去几年里,我参与了 多个项目,比如 Apple Watch 上的“体征”App, 以及 iPhone 和 iPad 上 “健康”App 中的睡眠功能。 没错,这些功能既需要操作直观, 又需要界面美观。 无论你是瞥一眼手腕,还是低头看手机。

    通过这些工作,我了解到扎实的 UI 布局基础是实现这一切的关键。

    今天,我将介绍 SwiftUI 布局中 那些通用的核心原则。 无论你正在哪个平台上开发。

    首先,我将回顾 SwiftUI 中一些对布局 尤为重要的概念性组件,

    随后讲解 SwiftUI 的布局机制。

    然后,我将通过示例向大家 展示如何使用 SwiftUI 获得可预测的结果。

    因此,我将从基础的视图开始讲起。

    正如 Leah 今早所描述的, SwiftUI 视图是一种轻量级模板, 用于描述屏幕上将显示的内容。

    视图是一种模板,它表示位置、大小和层级结构。

    SwiftUI 会创建轻量级的视图 结构体来描述屏幕上的内容, 并在后续更新时丢弃它们,同时生成新的结构体。

    SwiftUI 更新引擎仅 更新发生变化的 UI 部分, 从而确保根据状态变化获得可预测且高效的結果。

    这种效率源于 SwiftUI 的局部更新模型。 视图层次结构中某一 部分的更改不会波及到无关的子树。 因此,只有受影响的子视图才会被重新渲染。

    在 SwiftUI 中, 视图模板控制着从定位、 尺寸到渲染和状态更新的一切。

    既然已经介绍了什么是视图以及 SwiftUI 的更新引擎如何工作, 接下来我将展示当 SwiftUI 进行布局时, 这些概念是如何结合在一起的。

    在讲解布局机制时, 我将专注介绍我在“愿望清单” App 中构建的“行程卡”。

    行程卡片很好地展示了 SwiftUI 如何根据不同状态处理动态布局。

    在 SwiftUI 中,布局取决于状态。 这里所说的“状态”, 并非指 `@State` 属性包装器。 我指的是广义上的状态,

    例如行程的名称(如这里的 “Cali coastal trails”),

    或是行程图片的 URL。 SwiftUI 本质上将 状态与布局进行了抽象分离。

    虽然其他 UI 框架也能实现这一点, 但这需要付出一定的努力并保持严谨性。 而这种抽象是 SwiftUI 不可或缺的一部分。

    状态通过动态控制 UI 来驱动布局。

    状态还会填充每个视图中的内容, 例如屏幕上显示的字符串和图片。

    在其他框架中,状态变化需要手动更新 才能重新布局UI的特定部分。

    在 SwiftUI 中, 状态变化会自动重新生成受影响的视图模板, 从而始终确保它们保持最新状态。

    接下来,我将讨论我是如何构建愿望 清单App中旅行卡片布局的,如图所示。

    以此说明如何将布局与状态进行抽象分离。

    旅行卡片显示在纯色的深色背景上。

    它包含一个 `VStack`, 其中包含代表该

    旅行的图片以及显示旅行名称的文本视图。

    旅行图片视图有一个叠加层,用于显示活动数量,

    但仅当活动数量大于零时才会显示。 否则,该文本将不会被创建, SwiftUI 也不会渲染活动叠加层。

    视图的状态由模型中的行程独立控制。

    行程模型包含一个用于行程标题的名称字符串,

    以及一个用于确定应为该行程 渲染哪张图片的照片 URL。

    最后,它还包含一个活动字典。 字典中活动的数量用于 决定是否显示活动叠加层。

    这是一个关于状态如何控制 SwiftUI 布局以及值如何影响布局的简单示例。 在此示例中,活动数量被用于自定义视图的布局。

    接下来,我将解释 SwiftUI 中布局的工作原理。

    SwiftUI 布局的基本 前提是:容器会向其子视图 提出一个尺寸建议。

    该建议的尺寸受容器视图及 其所有上级容器视图的约束。

    每个子视图会通过计算并回报其首选大小来响应。

    SwiftUI 中不同的视图 具有不同的首选大小。

    颜色视图总是会占用所分配的全部空间。 它会扩展以填满可用空间。

    图像视图总是会占用其完整大小, 即使分配的空间较少也是如此。 这意味着图像可能会超出其容器视图的边界。

    使用 resizable 修饰符可覆盖此行为。 这样它就会占用所分配的全部空间。 就像颜色视图一样,即使最终看起来像这里的沿海 花朵那样被挤压变形。

    要保留图像的原始宽高比, 请将内容模式设置为 fit 或 fill。

    文本至少会占用显示省略号所需的空间。 文本只会占用其内容所需的空间。

    布局和 SwiftUI 是按层次结构进行的。

    容器视图会向每个子视图提出一个建议尺寸。

    假设建议尺寸是具体的。 例如,这个橙色方框展示了建议尺寸可能的样子。

    如果容器视图是App的根视图, 则建议尺寸即为设备尺寸;或者, 如果你应用了`frame` 修饰符, 建议尺寸即为该帧的大小。

    另一方面,有时在某个方向或两个方向上,

    建议尺寸均未指定。

    这意味着容器视图希望了解: 如果子视图完全不受约束,它会需要多少空间。 这就是子视图的理想尺寸。

    每个子视图会根据建议尺寸,返回其首选尺寸。

    与其他视图系统相比, 这是 SwiftUI 的一 种特殊且独特的行为。 建议值不仅会向下传递,也会向上传递。

    这个布局过程是递归的。 建议值从根视图开始, 沿整个视图层次结构向下传递。

    随后,响应值会向上回传。

    此时已掌握了各视图的尺寸。 根视图会告知所有子视图应绘制的位置。 子视图再告知其子视图, 如此循环往复,直至所有视图绘制完成。

    现在,我将再次带大家走一遍相同的遍历过程。 这次,我们将使用旅行卡片 中的实际视图和实际数值进行演示。

    旅行卡片出现在一个水平 滚动视图内的水平堆栈中。

    我希望所有旅行卡片——无论是“Kali”、 “Kyoto”还是其他卡片—— 都具有相同的高度,无论源 图像的大小或旅行名称的长度如何。

    我可以通过使用固定高度的帧来实现这一点。

    SwiftUI 为 `VStack` 提供了 无限宽度和220的固定高度。 在旅行卡片的根节点处。

    随后,该堆栈将220的高度 分配给旅行卡片的 ImageView。 这里仅 展示了一个固定高度帧的示例。

    ImageView 返回了其确切所需 尺寸: 185 × 150 点。

    外层堆栈减去返回的高度, 然后将剩余空间分配给包含行程名称的文本。

    名称文本返回其所需的空间 : 15 × 130 点。 我已经到达最后一个视图。

    现在,每个视图都已返回其所需的尺寸。

    这里指的是除“活动”覆盖层之外的每个视图。 我将在演示的后半部分再回到这个覆盖层。

    完成该过程。 `VStack` 将内部图像、 视图和文本的请求尺寸合并, 并返回该视图的最终请求尺寸。

    这就是 SwiftUI 布局的工作原理。

    总结一下, SwiftUI 布局是 从上到下遍历的。 尺寸信息会向上回传至根视图。

    在任何层级,可用空间都由容器视图提供。

    所需空间由子视图确定, 可能需要通过检查其自身的子视图来确定。

    只有当状态发生变化时,才会重新计算布局。

    视图模板会始终被重新创建。

    状态控制内容,因此当状态值发生变化时, 视图会自动更新。

    太棒了。现在是时候创建一些令人 惊叹的 SwiftUI 视图了。

    刚开始接触 SwiftUI 时, 我常会构建一个视图, 但有时却得不到预期的结果。 因此接下来,我将分享一些指南, 帮助大家通过保持布局简单且可组合, 从而获得可预测的结果。

    实现可预测布局的首要考虑因素是布局优先级。

    布局优先级用于确定视图 在间距调整和尺寸调整时的排列顺序。

    当空间不足以满足视图需求时,系统 会将更多空间分配给布局优先 级更高的视图。布局优先级通过 `layoutPriority` 修饰符设置,其默认值为零。 数值越高,优先级越高。 例如,优先级为3的视图优先级将高 于优先级为1的视图。

    这可能与你在缺陷跟踪系统中 习惯的情况相反——在那里, P1 级缺陷优先级最高, 但在此情况下则恰恰相反。 数值越大,优先级越高。

    在“愿望清单”App 中 我创建了一个“旅行”板块, 其中的卡片宽度更宽。

    我与我们的愿望清单 App 设计师 Maho 交流后, 我们认为这些宽幅的旅行卡片是 充分利用额外空间、 同时显示旅行副标题和创建日期的绝佳位置。

    有时,当一个容器视图中包含多个文本视图时, 文本可能会根据可用空间被截断或换行。

    在这个示例中,一旦 我添加了副标题和日期, 卡片左下角的“夏威夷美国”文本就会被截断。

    我可能无法确定可用空间有多少。 例如,不同尺寸的设备上可用空间可能各不相同。

    而且我可能也不清楚自己需要多少空间。 有些行程的副标题字符串较长, 因此通过在布局中标注不同文本的重要性, 你可以自主决定截断哪部分文本。

    你可以通过将文本的布局优先级 从默认值 0 提高到 1 等更高 数值来实现这一点。

    正如我之前提到的,堆栈会优先 为优先级更高的视图分配空间,

    因此副标题能获得所需的所有空间, 但这会导致右下角的日期文本被截断。

    我向我们的设计师 Maho 反映了这个布局问题。 她建议在空间不足时隐藏创建日期, 以便行程副标题能够完整显示。

    我认为这是一个很好的建议, 因为它避免了字符串被截断。 现在我将演示如何实现这一点。

    我将堆栈移入了一个适配视图中。 适配视图会评估其子视图。 它会按照你提供给初始化器的顺序,

    选择第一个理想尺寸(ideal size )能完全容纳在建议尺寸内的子视图。 这意味着你需要按优先级顺序提供视图。 通常这个顺序是从最大到最小。

    所以我添加了一个仅包含副标题的文本视图。 当视图放入后,如果堆栈 发生截断,"适合的视图" 会选择该文本视图。

    我相信这些改动会让 我们的设计师 Maho 很开心。

    接下来,我们的堆栈对齐功能会让 堆栈中的视图保持一致的对齐方式。 默认对齐方式是居中, 但也可以指定其他对齐方式。

    除了居中之外, H 型堆栈中的视图还 可以垂直对齐于顶部或底部, 也可以对齐于第一个文本 基线或最后一个文本基线。

    V 堆栈中的视图还可以按其前缘、 后缘等进行水平对齐。

    “愿望清单”App 中旅行 收藏的分节标题就是一个完美的例子。 默认情况下,堆栈使用居中对齐来对齐视图,

    但有时当你有一系列元素时, 这可能会显得对齐不齐。 在这种情况下,最好将它们全部对齐到基线。

    这里,章节副标题的子 视图正在使用默认对齐方式。 这意味着“显示全部”悬浮在副标题 文本所建立的视觉基线上方。

    通过将对齐方式改为“第一个文本基线”, 我将“显示全部”提升到了 与副标题相同的视觉基线上。

    现在,我将分享一些在 SwiftUI 中构建布局时需要考虑的要点。

    尽可能创建自适应布局,而不是显式布局。 自适应布局能让你更轻松地适配不同的设备尺寸、 窗口尺寸和平台。

    避免显式操作视图帧,不要为视图设置 显式的高度和宽度。 让它们自动扩展以填满可用空间。

    仅当无法通过自适应、 灵活的方式实现所需布局时, 才使用 `frame` 或 `position` 等视图修饰符。

    类似于 `ZStack`。 要为视图添加深度, 可以使用 `background` 或 `overlay` 修饰符。

    overlay 和 background 修饰符不包含在布局尺寸计算中, 且其尺寸始终与被修饰的视图相同。

    这就是为什么在之前的布局树遍历示例中, activities overlay 未 被纳入布局计算的原因。 它继承了其容器视图的计算尺寸。 默认情况下,图像视图。

    布局问题在所难免。 我至今仍会偶尔遇到这类问题。 接下来,我将分享一些用于识别 和修复这些布局问题的技巧。

    其中许多技巧都基于 SwiftUI 在快速原型设计方面的强大功能。 只需稍作调整,结果就会立即显示出来。

    一个简单的方法是在视图上添加彩色边框, 例如在图片上添加红色边框, 在文本上添加蓝色边框, 就像我在这里的旅行卡片中所做的那样。

    这种技巧对于理解堆栈布局和视图 周围的内边距特别有用。

    有时临时边框会相互重叠, 而我希望更直观地展示子视图的大小和位置。 在这种情况下,我会使用 半透明颜色的`overlay` 修饰符, 以显示子视图的完整范围及其层叠关系。

    在视图渲染时打印属性值也是一种有用的方法。

    你可能曾尝试使用 `print`, 却因编译器报错而感到失望。

    此处的错误信息显示: “buildexpression 不可用。 该表达式不符合视图规范。”

    出现此错误是因为 Swift 中的 `print` 表达式没有返回值,

    因此其返回类型为 `void`。 而 `void` 并非视图,但视图的主体确实支持变量声明。

    我可以通过声明一个占位变量来修复此错误。 现在,我可以在等号右侧 编写 print 表达式了。 这样编译时不会报错, 运行时也会将输出打印到控制台。

    接下来介绍 Xcode 预览和预览画布, Xcode 提供了一种快速查看 哪个视图对应哪段代码的方法。 点击画布底部的鼠标指针图标, 即可使预览区域可选中。

    然后,当我在编辑器中选中代码时, 预览区域会高亮显示相关的视图; 反之,如果我在预览区域中选中某个视图, Xcode 也会在编辑器中选中相应的代码。

    在我用于调试布局问题的工具箱中, 最强大的工具是 Xcode 的视图调试器。 通过运行App并使用视图调试器暂停它, 我可以展开所有视图, 然后选择单个子视图进行重点检查。 当我将 SwiftUI 与 UIKit 混合使用时,这种技术特别有效。 这让我想到一个重要点。

    SwiftUI 与 UIKit 布局兼容。 正如来自 Alltrails 的 James Graham 稍后将分享的那样。 如需了解更多相关内容, 请观看 WWDC 22 的视频。 将 SwiftUI 与 UKit 结合使用。

    既然我已经分享了 SwiftUI 布局的基础知识, 现在是时候将这些概念付诸实践了。

    学习的最佳方式就是开始动手构建。 我首先从一个自己喜欢的App中挑选了一个视图, 然后用 SwiftUI 重新实现它。

    Xcode 预览功能是快速 尝试不同布局和方法的绝佳 途径。

    利用打印和颜色 叠加等简单技巧,可以诊断遇到的任何布局问题。 你会惊讶于自己能如此迅速地识别并解决问题。

    感谢大家今天参与。 现在,请用 SwiftUI 打造一些特别的作品, 并享受接下来的讲座内容。

开发者页脚

  • 视频
  • Meet with Apple
  • SwiftUI 布局指南
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    • App Store
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • AI 与机器学习
    • Apple 智能
    • 音频与视频
    • 增强现实
    • 商务
    • 设计
    • 分发
    • 教育
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 安全性
    • Safari 浏览器与网页
    打开菜单 关闭菜单
    • 文档
    • 下载
    • 示例代码
    • 视频
    • 文档归档
    打开菜单 关闭菜单
    • 帮助指南与文章
    • 联系我们
    • 论坛
    • 反馈与错误报告
    • 系统状态
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件
    • “反馈助理”
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • 安全赏金计划
    • Security Research Device Program
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖
    • Apple 设计大奖
    • Apple Developer Academy
    • WWDC
    阅读最近新闻。
    获取 Apple Developer App,并在 bilibili 和微信上关注我们。
    版权所有 © 2026 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则