惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Help Net Security
Help Net Security
Latest news
Latest news
G
GRAHAM CLULEY
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
The Exploit Database - CXSecurity.com
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
U
Unit 42
人人都是产品经理
人人都是产品经理
小众软件
小众软件
Microsoft Security Blog
Microsoft Security Blog
C
CERT Recently Published Vulnerability Notes
V
Vulnerabilities – Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
NISL@THU
NISL@THU
AWS News Blog
AWS News Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Cisco Blogs
Google DeepMind News
Google DeepMind News
阮一峰的网络日志
阮一峰的网络日志
Project Zero
Project Zero
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Know Your Adversary
Know Your Adversary
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 热门话题
The Hacker News
The Hacker News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
T
Threat Research - Cisco Blogs
The GitHub Blog
The GitHub Blog
N
News and Events Feed by Topic
N
News | PayPal Newsroom
Attack and Defense Labs
Attack and Defense Labs
Cloudbric
Cloudbric
Scott Helme
Scott Helme
J
Java Code Geeks
H
Hacker News: Front Page
N
News and Events Feed by Topic
Recorded Future
Recorded Future
Martin Fowler
Martin Fowler
W
WeLiveSecurity
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
量子位
有赞技术团队
有赞技术团队

肘子的 Swift 记事本 | Fatbobman's Blog

当灵感跑在了结果前面 -- 肘子的 Swift 周报 #145 当每一次写入都有了新价格 -- 肘子的 Swift 周报 #144 当 Linux 成为“空气”:容器、Agent 与不再重要的“桌面之争” -- 肘子的 Swift 周报 #143 两个 SwiftUI 动画 Bug 排查小记 SPI 加入 Apple,Swift 迈向自举 -- 肘子的 Swift 周报 #142 Swift 还让你 Excited 吗? -- 肘子的 Swift 周报 #141 WWDC 26:AI 帮你看完了,然后呢? -- 肘子的 Swift 周报 #140 WWDC 2026 初印象:符合预期,但更务实 -- 肘子的 Swift 周报 #139 Core Data + Observation:从属性级响应到心智解放 稳定 > 新功能 -- 肘子的 Swift 周报 #138 用自定义 Layout 化解 SwiftUI List 的行高与间距跳变 从社区路标到生态基石:Dave Verwer 的新篇章 -- 肘子的 Swift 周报 #137 消失的 WWDC 愿望单 -- 肘子的 Swift 周报 #136 CocoaPods 正在退场,SwiftPM 才刚到第二章 -- 肘子的 Swift 周报 #135 让 AI 从称手到称心 -- 肘子的 Swift 周报 #134 Swift 并发正被更广泛地接纳 -- 肘子的 Swift 周报 #133 从 OpenSwiftUI 到 DanceUI:换个方式 Dive SwiftUI -- 肘子的 Swift 周报 #132 被 Vibe 摧毁的版权壁垒,与开发者的新护城河 -- 肘子的 Swift 周报 #131 苹果的罕见妥协:当高危漏洞遇上“拒升”潮 -- 肘子的 Swift 周报 #130 一墙之隔,不同的时空 -- 肘子的 Swift 周报 #129 我的 App 审核被卡了? -- 肘子的 Swift 周报 #128 CDE:一次让 Core Data 更像现代 Swift 的尝试 50 岁的苹果和 51 岁的我 -- 肘子的 Swift 周报 #127 2026 年,为什么我仍在思考 Core Data Macbook Neo:苹果重回校园的起点 -- 肘子的 Swift 周报 #126 跨域传递 NSManagedObjectContext 为什么在 Swift 6.2 中不再报错?真正的变化不在编译器 Xcode 26.3 + Claude Agent:模型替换、MCP、Skill 与自适应配置 macOS 录屏软件开发实录:从像素抓取到元数据重现 isolated(any) 与 #isolation:让 Swift 闭包自动继承隔离域 在 tvOS 上活下來:一個非典型播放器的工程實錄 告别“可移植汇编”:我已让 Swift 在 MCU 上运行七年 独立开发者的试炼:Zipic 从 0 到 1 的产品化之路 逃离 Mac App Store:如何从零构建独立应用的分发与售卖体系 为什么父视图无法修改子视图的 @State Partytown 实战:修复 GTM 自定义事件与 dataLayer 失效问题 Swift 6 编译加速:启用 Swift-Syntax 预构建 (Prebuilts) Swift 模块化:使用 package 关键字实现 Target 间安全共享 Monorepo 实战:解决 VSCode/Cursor 中 SwiftLint 配置失效问题 VSCode/Cursor 测试 Core Data:手动编译 xcdatamodeld 指南
从 Size Class 到可用空间,horizontalSizeClass 还可靠吗?
东坡肘子 · 2026-06-17 · via 肘子的 Swift 记事本 | Fatbobman's Blog

从 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 的 TN3192UIRequiresFullScreen 文档。

这也让 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 也显著降低了构建响应式界面的门槛,但开发者需要面对的场景实际上变得更多了。

固定画布时代正在结束,而围绕可用空间构建界面的时代,才刚刚开始。