Impeccable 原生适配指南:用 size class 重构而非缩放,把 iOS / Android 设计带到新上下文
【免费下载链接】impeccableThe design language that makes your AI harness better at design.项目地址: https://gitcode.com/GitHub_Trending/im/impeccable
原生界面适配(native adaptation)是 Impeccable 设计技能(skill)中adapt命令的一个专门分支:把一个已经成形的原生(native)设计——ios/android/adaptive平台——带到另一种设备类别、方向、平台或来源中去。它在 .opencode/skills/impeccable/reference/adapt.native.md 中定义,适用于 SwiftUI / UIKit、Jetpack Compose / Android Views、React Native、Expo、Flutter 等所有真实原生工程。本文将从"评估适配挑战"出发,展开手机→平板、方向与折叠屏、iOS↔Android 跨平台、Web→原生四条策略主线,并结合仓库中的平台基准、Slop 测试与验证流程,说明为什么适配的本质是"为新上下文重新思考体验",而不是缩放像素,并给出可以直接落地的实施与验收方法。
何时会用到这份原生适配参考
在 Impeccable 的目录结构里,adapt命令有两条参考路线:Web 项目(含移动端网页)走 .opencode/skills/impeccable/reference/adapt.md,而原生平台一律路由到adapt.native.md。在 .opencode/skills/impeccable/reference/adapt.md 开头就有明确分流说明:"Native platforms(ios/android/adaptive)route to adapt.native.md instead; if the project is native, switch to it now."
平台身份(ios/android/adaptive)在会话 Setup 阶段由context.mjs判定并写入setup.platform。.opencode/skills/impeccable/reference/routing.md 同时提醒:live与detect.mjs这类浏览器态工具只属于 Web,当setup.platform是ios/android/adaptive时不应使用——因为浏览器叠加层与 HTML 规则引擎对原生代码不生效。这正说明原生适配必须回到平台自身的参考体系(HIG / Material 3)来评估,而不是套用网页响应式的做法。
典型触发场景包括:产品从 iPhone 拓展到 iPad、新增折叠屏支持、把 iOS 设计移植到 Android(或反过来)、把一个"能跑的网页"重做成原生应用。执行前通常还需要一次性的额外上下文澄清:目标平台/设备与具体使用场景(即文档顶部的Additional context needed),因为它直接决定后续所有策略选择。
评估适配挑战:先问三个问题
动手改代码之前,先把"为什么要适配"讲清楚。参考文档给出了一个三段式评估框架:
- 源上下文(Source context):它当初是为谁设计的,隐含了哪些假设?(仅手机?仅竖屏?只遵循某一平台的惯用法?还是一个网站?)
- 目标上下文(Target context):目标设备类别(手机 / 平板 / 折叠屏)、方向、平台,以及使用姿态——单手行走途中使用,还是双手安坐时使用?
- 哪些会坏(What breaks):放不进目标的导航?被拉伸而不是被重构的布局?在该平台上根本不存在的手势或控件?
评估时最需要警惕的思维陷阱是全文档反复强调的一句判断:"The trap is treating adaptation as scaling. The job is rethinking the experience for the new context."(陷阱是把适配当成缩放;工作是为新上下文重新思考体验。)无论是网页参考还是原生参考都沿用了这一原则,这也解释了为什么整套策略都以"重构结构、替换隐喻"为基调。
策略一:手机 → 平板(iPad / 大屏)
平板上最典型的失败形态是"放大的手机 UI"。原生参考给出的对策是:
- 重构,而不是拉伸(Restructure, don't stretch)。iOS 用size classes,Android 用window size classes来切换结构,而不是按设备型号硬编码分支。
- 导航改变形态:iPhone 的 tab bar 到 iPad 可以升级为 sidebar(侧边栏);Android 的底部导航栏在展开宽度下应变成 rail 或 drawer。这与 android.md 中"Navigation bar (bottom, 3–5 destinations) on compact width; navigation rail or drawer on expanded width. Never ship a phone bottom-bar untouched on a tablet"的规则一一对应。
- 用足宽度:split view / master-detail(列表+详情并排)、多列网格、用 popover 替代手机上的 sheet。
- 把多任务当成一种尺寸,而不是边界情况:iPad Split View 与 Android 多窗口完全可能在平板上给你一个"手机宽度"的窗口。只要布局由 size class 驱动,这两种窗口尺寸就会被免费正确处理,无需专门的特判代码。
策略二:方向与折叠屏
- 横屏要做结构重构(并排窗格、重新布局控件),永远不要裁剪或信箱化(letterbox)画面。只有任务确实需要时才锁定方向——用锁定方向来掩盖布局缺陷属于文档明令禁止的行为(见后文 NEVER 清单)。
- 折叠屏(Android)要感知姿态(posture)与铰链(hinge):通过 window size classes 响应状态变化,并分别测试折叠(folded)、展开(unfolded)与桌面模式(tabletop)三种状态。
策略三:iOS ↔ Android 平台间移植
跨平台时的方法是翻译惯用法(translate idioms),而不是移植控件(transplant)。参考文档给出了一张实用的对照表:
| iOS | Android |
|---|---|
| Tab bar | Navigation bar / rail / drawer |
| Edge-swipe back、back chevron | Predictive Back 手势 / 返回按钮 |
| Switch、segmented control、系统 picker | Material switch、chips、Material picker |
| Action sheet | Bottom sheet / Material dialog |
| SF Symbols、SF Pro、Dynamic Type | Material Symbols、Roboto、sp 缩放 |
| 语义化系统颜色、材质(materials) | Material color roles、tonal elevation |
| 系统 push/sheet 转场 | Container transform、shared-axis、fade-through |
执行要点是:用目标平台的词汇重建导航与控件,同时把品牌表达层(brand's expressive layer)——调色板意图、字体点缀、动效个性——通过目标平台的主题系统继承过去。也就是说,被翻译掉的是"平台外壳",被保留的是"品牌内核"。
两份平台基准文件为这张表提供了更细的支撑:
- ios.md 要求遵循 HIG:语义化系统颜色(label、secondaryLabel、systemBackground、separator、tint)在深色模式与高对比度下自动适配,"raw hex breaks there";SF Symbols 要基线对齐、感知 Dynamic Type;edge-swipe back 是肌肉记忆,绝不关闭或覆盖;系统转场(push 滑动、sheet 升起)不得被自造转场对抗。
- android.md 要求 Material Design 3 作为规则手册:Material color roles 的角色 token 自动解析明暗与对比度变体;Dynamic Color(Material You)在 Android 12+ 上可从壁纸推导配色、并保留静态回退方案;sp 单位、非 px,让字号跟随系统字体设置;同一文件还特别提醒——"An iOS app wearing Android's skin"(套着 Android 皮肤的 iOS 应用)是 Android Slop 最常见的症状。
双端约束的交叉项也值得注意:即使是"Material everywhere"的跨平台应用,只要同时发往 iPhone,就仍须在 Apple 硬件上兑现 iOS 的系统保障——安全区 insets、Reduce Motion、edge-swipe back。
策略四:Web → 原生(把网站移植成应用)
原生参考对"移植网站"给出的要求是重新符合规范(reconform),而不是重新排版(reflow):
- 用平台自身的导航模型替换网页导航;
- 用平台控件替换 HTML 形态的控件;
- 把悬停(hover)暗示改成touch-first的交互;
- 把px 字号换成 Dynamic Type / sp。
完成后要整套走一遍平台参考全文——其中"slop test"(低质量原生判断测试,详见下节)就是验收及格线。换句话说:网页移植过来不算完成,直到它在每个平台上"读起来像原生"。
原生 Slop test:判断是否"像原生"
ios.md 与 android.md 各定义了自己的 Slop test,它们正是 Web→原生移植乃至一切原生适配的验收标准:
- iOS 版:"Would a fluent iPhone user trust this app, or pause at off-spec controls?" 最典型的破绽是"从网站移植来"的痕迹——自造导航栏、自定义返回手势、网页形状的按钮、依赖 hover 的暗示。
- Android 版:"Would a fluent Android user trust this app, or trip on off-spec components?" 最常见的是"套着 Android 皮肤的 iOS 应用"——照搬 iPhone 的纯底部导航、无视系统 Back 手势的返回箭头、Cupertino 造型的开关与对话框。
Impeccable 甚至把"越界的系统漂移"纳入了原生技术审计维度:audit.native.md 的 Platform Conformance 维度会专门核查 broken system gestures、inset violations、off-platform navigation、web-shaped controls、icon drift、system drift——因此一次/impeccable adapt之后,用/impeccable audit(native 变体)复检,就能用结构化评分确认适配是否真正落地。
实施与验证:从 size class 到真机证据
用 size class 驱动结构,永远不做设备型号检查
原生参考明确规定:结构必须由 size classes(iOS)/ window size classes(Android)驱动,绝不依赖 device-model 检查(例如按具体机型字符串判断)。理由很直接:适配要在"任意未来窗口尺寸"下都成立,设备清单永远是不完整、不可移植的特判。
每个新形态都要处理安全区与窗口 insets
notch、Dynamic Island、铰链(hinge)、状态栏、键盘(IME)——任何新增的配置形态都必须遵守安全区(safe area)与窗口 insets。ios.md 与 android.md 都把它列为布局第一原则:iOS 上"no controls under the notch, Dynamic Island, home indicator, or rounded corners";Android 上要 edge-to-edge 应用 status bar、navigation bar、display cutout 与 IME insets,使内容永远不被系统栏或键盘遮挡。
先模拟器取广度,再真机取真相
验证路径分两层:
- 每个发布平台至少测一台手机 + 一台平板,两种方向都要覆盖,支持分屏的平台上要测分屏;
- 在支持的平台上测"新配置"的全部安全区/insets 场景。
具体取证方式应遵循各平台基准的 Verifying the build 章节:
- iOS:截图只能来自 Simulator,不能用浏览器。用
xcrun simctl io booted screenshot <path>抓取(多台运行时用 UDID 替换booted);用xcrun simctl ui booted appearance dark切换深色外观,并在大号 Dynamic Type 下复查截断。 - Android:截图来自 emulator 或真机,用
adb exec-out screencap -p > <path>(多设备用adb -s <serial>);adb shell cmd uimode night yes切换深色主题,adb shell settings put system font_scale 1.3(用后还原1.0)检验大字体的裁切问题。
两份基准给出了同一句忠告:"Simulators give breadth; posture, gestures, and performance need hardware."模拟器负责覆盖面,而姿态、手势与性能必须上真机,并且要在交付证据时说明"这份证据来自模拟器还是硬件"。
收尾交接
当每个上下文下的适配都"感觉是原生"之后,把结果交给/impeccable polish做最后一轮打磨。这里的语义是:adapt负责把结构、导航与控件改造成原生形态,polish再在"不偷换设计、只收尾质量"的约束下做最终一致性处理(详见 .opencode/skills/impeccable/reference/polish.md)。
NEVER:原生适配的绝对禁区
参考文档以一组禁令收尾,这同时也是适配完成度的自检清单:
- 绝不在平板上交付一个被拉伸的手机布局(Ship a stretched phone layout on a tablet);
- 绝不把一个平台的控件或导航移植到另一个平台(Port one platform's controls or navigation onto the other);
- 绝不在小设备上隐藏核心功能——如果它重要,就让它可用(Hide core functionality on smaller devices);
- 绝不为了回避布局缺陷而锁定方向(Lock orientation to dodge a layout bug);
- 绝不只信模拟器——姿态、手势与性能必须经真机验证(Trust simulators alone)。
小结:把"原生感"当作适配成功的判据
回顾整套方法,可以归纳为一条可执行的主线:评估时问清"源上下文假设了什么、目标上下文需要什么、什么会坏掉";实施时用 size class 重构结构、用目标平台词汇重建导航与控件、把品牌层通过主题系统带过去;验证时先模拟器铺广度、再真机取真相,并以平台 Slop test 作为验收及格线。
如果你手头正是一个ios/android/adaptive工程,需要跨设备、跨方向或跨平台改造,直接以 adapt.native.md 为行动底稿,配合 ios.md 与 android.md 两份平台基准共同执行即可;改造完成后,用/impeccable polish收尾,用原生变体的/impeccable audit(见 audit.native.md)复查 Platform Conformance 与 Adaptivity 评分,就能形成"适配—审计—打磨"的完整闭环。
【免费下载链接】impeccableThe design language that makes your AI harness better at design.项目地址: https://gitcode.com/GitHub_Trending/im/impeccable
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考