dctc_青龙 dctc_青龙 当前离线 积分5543 258主题1回帖143银子 超级版主 积分5543 关注TA 发消息 发表于 2026-10-25 07:02 | 显示全部楼层 |阅读模式 [TITLE] iPhone Duo 双屏适配排查:旧尺寸分支与新几何断点方案对比 [/TITLE] [CATEGORY] phone [/CATEGORY] [KEYWORDS] 华强北,iPhone Duo 双,科技数码,AI,热点 [/KEYWORDS] [FID] 43 [/FID] [CONTENT]# iPhone Duo 双屏适配排查:旧尺寸分支与新几何断点方案对比 折叠机真正的麻烦,不是"屏幕上多出一块",而是窗口几何从启动到退出随时会变。iPhone Duo 这轮双屏适配返工,八成集中两类代码上:还在用 UIScreen 的老尺寸分支,以及刚迁到 scene 几何、断点却选错的新代码。看着像同一个病,排查路径压根不是一条。10 月 16 日预售、10 月 23 日发货,机器跟着 iOS 27.1 一起到用户手里,测试群里已经开始冒问题了。 ## 一、展开态错位:UIScreen 和 Scene 几何的取值差异 按 The Information、彭博和天风国际的供应链说法,苹果首款折叠走书本式内折,早期传的是内屏 7.8 英寸、外屏 5.5 英寸,量产窗口落在 2026 年前后。真机公布的数字收了收:内屏 7.6 英寸折叠 OLED,1878×2670、430 ppi;外屏 5.4 英寸,1398×2034、460 ppi,两块都支持 120Hz ProMotion,户外峰值 3000 尼特。SDK 这边,从 iOS 26 起 UIScreen 系列接口被标记弃用,几何信息改由 UIWindowScene 的 effectiveGeometry 和 coordinateSpace 给。 这组像素值有个坑,踩的人不少。按 3x 折算大概 626×890 pt 和 466×678 pt,可苹果从没公布过任何 point 规格。HIG 的布局规格表还停在 iPhone 17 Pro Max 和 iPhone Air,App Store Connect 的截图规格最高也只到 6.9 英寸级。换句话说,你算出来那两个数只是算术结果,不是官方值。硬编码进去,等于自己埋雷。 老方案最大的隐患,是把 `UIScreen.main.bounds` 当布局基准。折叠态切到展开态,UIScreen 返回的还是物理屏尺寸,窗口在分栏、留白、安全区上另有一套规矩。结果就是视图宽度比窗口多出几十 pt,内容压到铰链那边去。排查不用一层层核对约束,先把几个值并排打出来看看: ```swift let geo = windowScene.effectiveGeometry print(geo.coordinateSpace.bounds) // 场景自身坐标系下的尺寸,布局用它 print(geo.systemFrame) // 场景在系统坐标系里的位置 print(geo.interfaceOrientation) // 替代已弃用的 windowScene.interfaceOrientation print(geo.isInteractivelyResizing) // 是否正在被拖动缩放 print(view.window?.bounds) // 窗口实际尺寸 ``` `coordinateSpace.bounds` 和 `view.window.bounds` 对不上,毛病就在取值源。对得上但子视图照样错位,才轮到约束和容器背锅。还有个容易忽略的差异是长宽比:两块屏分别 1.42 和 1.45,卡在 iPad 的 1.33 和 iPhone 的 2.17 中间,接近 3:2。按 19.5:9 竖排设计的页面搬过来,不是上下留白就是内容被裁,16:9 视频必然黑边。 ## 二、折叠瞬态:重复刷新与状态丢失 一次展开,sizeClass、安全区、几何三类变化会连着触发。把布局收口到 `viewWillTransition(to:with`,回调结束后的下一帧统一更新,比在 `layoutSubviews` 里反复判宽度阈值稳得多。列表在折叠瞬间跳回顶部?多半不是渲染的锅,是数据源重建被写进了尺寸变化分支。把重建逻辑和布局逻辑拆开就行。 这块细节值得多说两句。PostHog 在 iOS SDK 的 issue #848 里记了一组实测:iPhone Duo 模拟器、iOS 27.1,手折一次,窗口从 466×678 直接变成 951×669,设备没转、key window 也没换。结果 `UIDevice.orientationDidChangeNotification` 和 `UIWindow.didBecomeKey` 都不发,靠这两个通知刷缓存尺寸,必然滞后一个事件。`UIScreen.didConnectNotification` 倒是发了,可载荷是屏幕的 669×951,方向跟窗口的 951×669 整个反着。只有 `viewWillTransition(to:with` 在切换当下就把正确尺寸当参数递给你——这时候 `window.bounds` 还停在旧值上。 代价得认。这方法是全局 UIKit 钩子,要 swizzle,而且只对 key window 的 root view controller 生效,否则拿到的是子控制器的宽度(实测侧栏 320,窗口 951)。 还有条明确的禁区:别对 `effectiveGeometry` 做 KVO。苹果说 scene 属性不保证 KVO 兼容,它在 27.1 上确实能跑,但属于未文档化行为,失败方式是宿主 App 直接崩。正规入口是 scene delegate 的 `windowScene(_:didUpdateEffectiveGeometry`,回调参数给的是旧几何,当前值还得从 `windowScene.effectiveGeometry` 读。这个回调在场景换屏时也会触发,哪怕逻辑尺寸没变,所以别无条件重排,先比尺寸。拖动缩放过程中要做重活——重建大纹理、重生成图片、刷昂贵缓存——拿 `isInteractivelyResizing` 挡住,等松手再说。 ## 三、安全区与铰链遮挡 折叠设备的安全区不是四边等宽。横置时左右 insets 互换,竖置时上下不同。把 `safeAreaInsets` 当常量缓存,一转就废;该按当前窗口几何实时读,铰链那侧额外留一段可配置间距。 旧代码里最常见的写法是 `view.bounds.width - view.safeAreaInsets.left * 2`,默认左右对称。可 iPhone Duo 外屏的竖排系统栏会挂在一侧,展开态左右 insets 本来就不等。正确写法:`view.bounds.inset(by: view.safeAreaInsets).width`。 iOS 27.1 补了一组铰链相关 API,专门解决 safeAreaInsets 覆盖不到的场景。`reservedRegions(kind: .division)` 返回折痕占的区域,只在折起来时生效,展平后失活、宽度归零。`reservedRegions(kind: .occlusion)` 返回摄像头这类遮挡——外屏前摄常驻,还会扩成灵动岛;内屏 FaceTime 摄像头工作时也挡一块。传 `.includeInactive` 能提前拿到未激活区域,比如让网格永远优先偶数分栏,保证没单元格跨在折痕上。 判断标准其实很简单。系统容器(NavigationStack、NavigationSplitView、TabView)自己会避开折痕,弹窗和 popover 也会挪位,分屏直接切 50/50。List 和 ScrollView 是连续内容,苹果建议让它自然滚过折痕,别位移。只有自己画的 bar、自定义底部面板、贴边控件,才必须查 reserved regions——这类东西光靠 safeAreaInsets 是不够的。 位移本身也有讲究。能独立成立的元素单独挪,属于一组的整体挪;别挪太远,让人找不到原位;滚动内容一律不挪。姿态上,书本态弹窗靠 trailing 一侧(合盖后那儿正好还在视野里),桌面态上半屏适合放远看的内容,下半屏放操作,因为底下更稳。 ## 四、启动就挂:UIScene 与新 SDK 门槛 比布局错位更严重的,是根本起不来。用最新 SDK 构建时,UIScene 生命周期是硬性要求,没有 UISceneDelegate 的应用在 iPhone Duo 上直接不启动——这是启动崩溃,不是视觉瑕疵。所以"要不要重写"得拆两半答:不重编译也能跑,但要好看、要能在 2027 年 4 月之后继续上架,就得动。 SDK 阶梯大致三级。不重编译,App 原样跑;用 iOS 27 SDK 构建,内容能延到内屏状态栏左侧;用 27.1 SDK,内容能到屏幕边缘,系统导航和工具栏按钮转竖排。2027 年 4 月起,传 App Store Connect 的包必须用 iOS/iPadOS 27 SDK 或更新版本,同时还会校验 Info.plist 里的启动屏配置。 竖向系统栏有个隐性坑:只有系统容器自己拥有的 bar 会跟着竖过来。手写的 UIToolbar、UINavigationBar、UITabBar 内容完全不参与新布局。表现就是别人家 App 侧边一排整齐图标,你的还横在顶上压内容。27.1 给了 `toolbarVerticalBehavior`、`toolbarVerticalCompressionBehavior`、`axisBehavior` 和 `toolbarVerticalEdge` 去微调,前提是先把自定义 bar 换回系统容器。 ## 五、用 sizeClass 替代 idiom 和 orientation 内屏两个维度都报 regular,外屏报 compact 宽度,两套布局分支就能覆盖整机。`userInterfaceIdiom` 在这台设备上仍旧返回 phone——它在 iPad 上的 iPhone App、Mac 上的 iPhone 镜像里本来就失真,折叠屏只是把这种失真弄得肉眼可见。朝向同理,iOS 27 起在可调整环境里它只是"偏好",内屏根本不理会 `supportedInterfaceOrientations`,按朝向分支的布局会走进死路。 SwiftUI 用 `@Environment(\.horizontalSizeClass)`,UIKit 用 `registerForTraitChanges([UITraitHorizontalSizeClass.self])`,都比监听设备朝向稳。50/50 分屏下苹果还没公布 size class,按 compact 宽度做假设、留好降级分支,别写死。 ## 六、动手前的排查清单 迁移的成本,主要不在写新代码,在删旧假设。grep 几个关键词,基本能把雷排完: - `UIScreen.main`(bounds、scale、brightness 全算) - `userInterfaceIdiom`、`interfaceOrientation`、`UIDevice.current.orientation` - `UIRequiresFullScreen`、`supportedInterfaceOrientations` - 自己 new 出来的 `UIToolbar`、`UITabBar`、`UINavigationBar` - `safeAreaInsets.left * 2` 这类对称假设 - 单例里缓存的屏幕尺寸、写死的宽度常量 - 硬编码的 "Face ID" 文案——这台是侧边电源键 Touch ID,开合状态都能用,该读 `LAContext.biometryType` 多窗口顺手也检查一下。新场景只在显示屏上开,被拒绝是正常现象,优先用 `UIWindowScene.ActivationAction`,窗口不可用时它会自己隐藏。 ## 两套方案对比 | 维度 | 旧尺寸分支(UIScreen + 固定阈值) | 新几何断点(effectiveGeometry + sizeClass) | |---|---|---| | 兼容性 | 老工程零改动即可编译,但 iOS 26 后持续告警 | 需 iOS 26 及以上,旧系统要保留降级分支 | | 改动量 | 小,集中在布局文件 | 中,涉及几何取值与状态收口 | | 几何精度 | 低,物理屏尺寸与窗口尺寸混用 | 高,直接对应窗口实际可用区域 | | 瞬态稳定性 | 依赖宽度阈值,折叠瞬间易多次重排 | 回调收口后单次重排,抖动少 | | 维护成本 | 每新增形态追加一条 if 分支 | 断点集中配置,新增形态只加数据 | | 启动门槛 | 缺 UISceneDelegate 在新 SDK 下直接不启动 | 天然按 scene 组织,顺手合规 | | 铰链与系统栏 | 拿不到折痕信息,自定义 bar 不会竖排 | 可接 reservedRegions、ArrangementView、竖向工具栏 | | 生态支持 | 官方已弃用,第三方库跟进滞后 | 官方推荐路径,新 API 持续补齐 | 结论挺清楚。新立项直接走几何断点,别为省两天时间攒技术债;存量工程按"先换取值源、再收口状态、最后清阈值分支"的顺序迁,比一把梭重写风险低。真想用上 27.1 的折痕和排布能力,还得再往前一步——把自定义容器换成 ArrangementView,让它按尺寸类、长宽比和折痕状态自己判断并排还是叠放。 ## 适用场景 外屏单手那类轻量场景——消息、支付、扫码——尺寸分支还撑得住。碰上分栏阅读、视频、多窗口协作的展开态,必须走几何断点,不然折一次重排一次。跨端团队如果 iPad 和折叠机一起维护,最好共用一套断点定义,别让两套阈值互相打架。 有个中间地带值得单拎出来说:AI 摘要、实时字幕、翻译浮层这种随内容生长的卡片。它们既不是固定侧栏,也不是全屏页面。展开时贴在正文旁、折叠时收进底部抽屉最自然——这正好是 ArrangementView 的 split 和 overlay 两种风格各自擅长的形态。用固定宽度硬撑,展开态剩一大片空白,折叠态又把正文挤没了。 对线下生意来说,双屏带来的第一波需求反而很朴素。等真机铺到华强北柜台,贴膜和保护壳要按 5.4 和 7.6 两个尺寸分别备货,铰链附近的膜还得留折痕余量。这跟过去一套模具通吃所有 iPhone 的逻辑,完全是两回事。 ## 趋势判断 折叠屏的适配重心,正从"检测到形态"挪向"响应几何变化"。苹果在 iOS 26 弃用 UIScreen,实质是把窗口当可变量,而不是固定画布;到 27.1 再补折痕区域和排布容器,等于承认布局该是"给多少空间排多少内容",而不是"认出型号再套模板"。接下来一年,谁先把布局从尺寸判断改成几何驱动,谁在下一轮形态变化里就能少改一次代码。 真机已经发出去了,第一批兼容问题这两周会集中冒头。2027 年 4 月的上架门槛,可不会等谁。你们团队现在是哪种写法?评论区聊聊。 [/CONTENT] 快速回复 回复 使用道具 举报