从 WWDC 26 开始,iPhone 应用在 iPhone Mirroring 到 Mac 时,其窗口尺寸将支持自由调整。与此同时,iPhone-only 应用在 iPad 上运行时,也会进入可变尺寸环境。即便不升级真机系统,开发者仍可以通过 Xcode 27 的 Preview 或 Device Hub 中的 iOS 27 模拟环境提前体验这一变化。
不过,这次更新带来的影响远不止“iPhone 应用可以调整尺寸”这么简单。它正在改变许多开发者长期以来对布局系统的理解。一些过去常被用作布局依据的 trait,例如 horizontalSizeClass 已不再适合作为窗口宽度的主要判断依据。
那么,这种变化究竟是一次突然出现的转向,还是 Apple 多年布局下的必然演进?本文将对此进行探讨。
我的 iPhone 应用变丑了
最近,我正在重构自己的一个老项目,尝试用新的开发思路和 API 重新实现整个应用。
当我看到 WWDC 26 上展示的 iPhone 应用可调整尺寸能力后,第一时间便测试了自己应用在这一场景下的表现。考虑到应用本身已经为 iPhone、iPad 和 macOS 预留了适配逻辑,我原本以为,在 Device Hub 中拉伸窗口宽度后,现有的自适应布局足以应对这种变化。
但出乎意料的是,NavigationSplitView 并没有从单列切换到多列,Tab 相关组件也没有出现预期中的形态变化。
当我检查环境中的 horizontalSizeClass 后发现,无论窗口尺寸如何变化,它始终保持为 compact。
不过,当应用以 pad idiom 运行在 iPad 上时,horizontalSizeClass 仍会在一定范围内随着窗口尺寸变化而调整。如果移除 iPad device family,让应用以 iPhone-only 兼容模式运行在 iPad 上,其行为又会变得与 Device Hub 中的 iPhone host 十分接近。
起初,我一度怀疑这是 Beta 1 中尚未修复的问题。直到观看了 WWDC 26 的 Session《Modernize your UIKit app》后,我才意识到这其实是 Apple 有意设计的结果。
这不是 Beta Bug:WWDC26 给出的新契约
Apple 在 Session 278《Modernize your UIKit app》中,明确将 iPhone 应用纳入动态尺寸环境:
- iPhone Mirroring on Mac 中,iPhone 窗口可自由调整尺寸。
- iPhone-only 应用在 iPad 上运行时,也会进入可变尺寸环境。
- 应用应能够在运行时适配任意 scene size,而不是假设固定设备比例。
UIScreen.main与 screen bounds 不再可靠,应使用 window scene 的 effective geometry,或者 view / superview 的实际可用尺寸。userInterfaceIdiom不再适合作为布局决策依据。- iPhone 应用在 iPad 或 Mac 镜像环境中仍可能运行在 phone idiom 下,因此 phone idiom 与窄屏布局不再等价。
- orientation 同样不再可靠。在可调整尺寸环境中,支持方向更接近一种偏好;即使窗口宽高比发生变化,系统仍可能保持 portrait orientation。
- 如果需要精细控制布局,应优先使用 surrounding view size。
这也解释了我之前遇到的反直觉现象:即便窗口已经被拉宽,iPhone host 中的 horizontalSizeClass 仍可能保持为 compact。
这不是 Beta Bug,而是 Apple 有意将「宿主语义」与「可用几何空间」拆分后的结果。
horizontalSizeClass 到底还可靠吗?
答案是:可靠。
只是它可靠表达的是当前 trait environment 的粗粒度语义,而不是窗口宽度本身。
这或许也是今年最容易被误读的地方。iPhone host 中的窗口变宽,并不意味着系统一定会将 horizontalSizeClass 切换到 regular;反过来,即使是较窄的 iPad 窗口,也可能因为所处的 idiom、scene、presentation 或容器环境不同,而表现出完全不同的 trait 结果。
对于开发者而言,真正重要的变化并不是“iPhone 变成了 iPad”,而是:
userInterfaceIdiom:只说明应用运行在哪种宿主语义下,不应再作为布局决策依据。horizontalSizeClass:是系统对 trait environment 的粗粒度上下文判断,而不是连续的宽度传感器。- view 或 scene 的 geometry,才是应对任意窗口尺寸、宽高比变化、浮窗以及镜像场景时更精细的布局依据。
因此,horizontalSizeClass 依然适合表达系统容器语义,例如菜单是否折叠、系统 Tab 或 Sidebar 是否可用;但对于应用自身的布局断点,例如“宽度超过多少后切换为双栏布局”或“显示侧边导航”,则应该依据当前 root view、container view 或 scene 的实际可用尺寸进行判断。
从设备到 scene,从方向到可用空间
如果只关注 WWDC 26,这一变化很容易被理解成 iPhone Resize 带来的新问题。
但如果把过去几年的线索串联起来看,会发现 Apple 实际上一直在朝着同一个方向推进:不断削弱「设备类型 + 屏幕方向」作为布局决策依据的重要性,并逐步将开发者引向 scene、trait hierarchy 与可用空间。
- 2014:Apple 在 iOS 8 中引入 Size Class。今年的 Session 278 再次强调了这一设计理念:设备旋转本质上只是一次 bounds 的变化。
- 2019:iPad 多窗口与
UIScene打破了“一个 App 只有一个 UI 实例”的传统认知。Scene 开始拥有自己的生命周期、状态恢复、屏幕和几何信息。 - 2022:iPadOS 16 的 Desktop-Class iPad 更新,将 iPad 从“放大版 iPhone”进一步推向更高密度、更接近桌面生产力的界面形态,为后续的可变空间设计奠定基础。
- 2023:Session《Unleash the UIKit trait system》进一步明确了这一方向。环境信息被塑造成沿着 scene、window、presentation、view controller 与 view 逐层传播的上下文,而不再是单一的设备事实。这也解释了为什么开发者在 iPad window、sheet 或 split column 中读到的
horizontalSizeClass往往与直觉不同。 - 2024:Tab Bar 与 Sidebar 被视为同一导航层级在不同空间条件下的不同呈现形式,为后续导航形态自动切换建立了统一语言。
- 2025:iPadOS 进一步向 macOS 靠拢,窗口、菜单栏、指针和多窗口工作流都更加桌面化。
- 2026:iPhone 应用进入可变尺寸环境,“iPhone 应用只服务固定手机比例”的假设正式失效。
iPad 的 Full Screen 说明了同一个趋势
iPad 的 Full Screen 变化其实也在说明同一个趋势。
Apple 并没有取消用户选择全屏工作方式的权利,但正在逐步收回开发者通过 UIRequiresFullScreen 将应用锁定在旧兼容模式中的能力。
在 iPadOS 26 中,用户仍然可以通过 Settings 或 Control Center 在 Full Screen Apps、Windowed Apps 和 Stage Manager 之间进行选择;但对于开发者而言,UIRequiresFullScreen 已经被定义为 deprecated compatibility mode,并将在未来被系统忽略。
换句话说,全屏从过去的“开发者强制要求”,逐渐转变为“由用户和系统共同决定”。关于这一点,可以参考 Apple 的 TN3192 与 UIRequiresFullScreen 文档。
这也让 iPad 的 Full Screen 与 iPhone Resize 回到了同一条主线:开发者可以表达偏好、最小尺寸以及临时方向锁定,但不应再假设自己拥有一块固定不变的画布。
回到我的项目:用 geometry 做自己的布局策略
理解这些规则之后,我开始重新审视自己的应用应该如何应对 iPhone Resize。
虽然可以根据场景 geometry,在某棵 SwiftUI 子树中注入 \.horizontalSizeClass = .regular,让部分容器进入 regular 语义,但这并不适合作为全局策略。
这种做法会影响整棵子树中所有读取该环境值的视图,而不同组件在「phone idiom + injected regular」组合下的表现并不一致。
例如,NavigationSplitView 可以展开侧边栏,但在我的测试中,TabView(.sidebarAdaptable) 并不会因此自动变成 iPad 风格的 Sidebar。
这并不意味着 UIKit 在 iOS 27 中新增的 tab sidebar opt-in API 没有价值,而是说明“宽 iPhone 窗口”与“iPad 导航环境”并不是同一个概念。
换句话说:宽窗 iPhone 仍然是 iPhone 的自适应呈现,而不是完整意义上的 iPad 产品界面。
结合自己的应用场景,我发现 Apple 在 2024 年提出的“Tab Bar 与 Sidebar 是同一导航层级的不同呈现形式”这一理念,非常适合当前项目。
因此,我为应用制定了如下策略:
- 使用 geometry 判断当前是否进入宽屏状态。
- 在 iPhone host 且处于宽屏时,显示自定义 Sidebar,并隐藏 Tab Bar。
- Sidebar 中的按钮仍然通过状态驱动 Tab 切换。
- iPadOS 下不启用这套 iPhone 专属逻辑,优先让系统组件根据自身 trait 与 geometry 自适应。
- macOS 端彻底舍弃 Tab 结构,直接使用 Sidebar 导航。
固定画布时代结束了
未来,开发者能够表达的将更多是偏好,而不再是对界面的绝对控制。
例如:
- 使用
UISceneSizeRestrictions表达 scene 的 preferred minimum size。 - 在 SwiftUI 中通过
windowResizability(_:)与内容最小尺寸表达窗口偏好。 - 使用
prefersInterfaceOrientationLocked表达临时方向锁定需求。 - 通过
windowScene(_:didUpdateEffectiveGeometry:)观察 scene geometry 变化。 - 使用
UIWindowSceneGeometry.isInteractivelyResizing或 SwiftUI 的onInteractiveResizeChange(_:)区分交互式调整过程与最终状态。
用户拥有了最终的呈现选择权,而开发者则需要提前考虑各种可能出现的展示形态。尽管越来越多系统组件具备了良好的自适应能力,SwiftUI 也显著降低了构建响应式界面的门槛,但开发者需要面对的场景实际上变得更多了。
固定画布时代正在结束,而围绕可用空间构建界面的时代,才刚刚开始。