OpenClaw iOS 设计系统实战:iOS 26 Liquid Glass 与 iOS 18 兼容回退的工程实践
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
OpenClaw 的 iOS 客户端在 DESIGN.md 中确立了一套以「原生优先 + Liquid Glass 克制使用 + iOS 18 兼容回退」为核心的设计系统。本文将围绕该文档展开,先梳理设计原则与几何 Token,再逐层讲解组件库、Liquid Glass 使用边界、黑色侧边栏的响应式实现,最后给出可落地的 Review Checklist 与源码佐证路径,帮助你在自己的 SwiftUI 工程中复刻这套「既有 iOS 26 新质感、又保持 iOS 18 稳定基线」的方案。
事实说明:iOS 26 / Liquid Glass 相关能力来自 DESIGN.md 中引用的 Apple 公开文档(Adopting Liquid Glass、Applying Liquid Glass to custom views、WWDC25 Session 323),本文仅按仓库文档转述;所有组件名、代码细节与行为以仓库源码为准,不再重复给出外部链接。
设计原则:原生结构优先,玻璃只做点缀
OpenClaw 的 iOS 设计系统遵循「跟随 iOS 26 原生设计语言,同时保持 iOS 18 部署目标」的总体策略,代码层由 project.yml 中的deploymentTarget: iOS "18.0"与xcodeVersion: "26.0"双重约束(第 5-6 行)。文档给出的核心原则如下:
- 优先使用 SwiftUI 系统结构:
NavigationStack、List、Form、toolbar、sheet 和系统控件优先于自定义实现,因为它们会自动适配当前平台外观。 - 根导航使用单一黑色侧边栏:在宽屏横屏下为常驻栏,在手机、竖屏和窄布局下则作为推入式抽屉层,压在内容后面。
- Liquid Glass 只用于导航与交互控件:不要给每一张卡片、每一行或每个状态表面都加玻璃效果。
- 先用排版、间距、分组建立内容层级,再考虑背景装饰。
- 使用语义色:红色=破坏性或已停止,橙色=需要注意,绿色=健康;中性操作用应用强调色(accent)。
- 保留辅助功能底线:Dynamic Type 动态字体、VoiceOver 标签、Reduce Motion、Increased Contrast,以及 44pt 触控目标。
- 连续圆角与同心几何:嵌套控件应视觉上跟随其容器的形状。
这七条原则可以被概括为一句话:系统结构打底、玻璃效果点缀、语义色传达状态、可访问性永不妥协。
几何 Token:OpenClawProMetric与共享尺寸体系
文档指定 OpenClawProComponents.swift 中的OpenClawProMetric为共享几何的唯一事实来源(single source of truth):
| Token | 用途 | 源码值 |
|---|---|---|
pagePadding | 标准页面留白(gutter) | 16 |
cardRadius | 内容分组圆角 | 16 |
controlRadius | 内嵌控件圆角 | 12 |
drawerRadius | 侧边栏抽屉展开时紧凑内容的全角圆角 | 见下文说明 |
compactControlSize | 紧凑圆形控件尺寸 | 36 |
bottomScrollInset | 持久导航上方的滚动间隙 | 96 |
在源码中(OpenClawProComponents.swift)可见实际定义:pagePadding = 16、cardRadius = 16、controlRadius = 12、compactControlSize = 36、bottomScrollInset = 96。其中drawerRadius在 Token 枚举中未显式出现,而是体现为抽屉组件自身的圆角常量——RootSidebarDrawer.swift 定义了cornerRadius: CGFloat = 28与topLeadingRadius: CGFloat = 8,分别对应抽屉内容卡的全圆角与顶部前缘小圆角。
除了这套主 Token,源码还提供了补充性的次级体系,方便局部布局引用:
OpenClawSpacing(OpenClawProComponents.swift):space1 = 4、space2 = 8;OpenClawRadius(同文件 L17-L21):xs = 8、sm = 10、md = 12。
文档强调:功能局部的布局枚举可以定义行高与网格尺寸,但应引用共享圆角,而不是引入新的卡片形状。这样可以保证整个 App 的视觉一致性,也让后续统一调整主题时只改一个文件。
组件库清单:内容、指示器与玻璃控件
文档列出的核心组件全部位于 apps/ios/Sources/Design/ 目录,源码逐项对应如下:
| 组件 | 作用 | 源码位置 |
|---|---|---|
OpenClawProBackground | 分组页面背景 | OpenClawProComponents.swift(Color(uiColor: .systemGroupedBackground).ignoresSafeArea()) |
ProCard | 安静的卡片内容分组,永远不使用 Liquid Glass | 同文件 L52-L68(通过proPanelSurface渲染圆角、描边与可选阴影) |
ProIconBadge/ProValuePill | 紧凑语义指示器 | 同文件 L187-L200 / L547-L564 |
OpenClawNoticeBanner | 共享的连接与运行时通知横幅 | 同文件 L309-L394 |
OpenClawAdaptiveHeaderRow | 自适应目标页标题行 | 同文件 L396-L479(用ViewThatFits在横排与堆叠布局间切换) |
OpenClawGlassControlGroup | 相邻玻璃控件的性能与形态边界 | 同文件 L290-L302(iOS 26 用GlassEffectContainer(spacing: 8),回退为直接输出内容) |
OpenClawSidebarPalette | 固定黑色侧边栏色板,任何外观模式下保持深色 | OpenClawSidebarPalette.swift |
OpenClawSidebarRevealButton/OpenClawSidebarHeaderLeadingSlot | 共享的 leading 工具栏入口 | OpenClawProComponents.swift |
openClawGlassButton(prominent:tint:) | iOS 26 玻璃按钮 + iOS 18 有边框回退 | 同文件 L98-L127、L155-L157 |
openClawGlassButton的双路径实现
这是整个设计系统中「新系统能力 + 旧系统回退」模式的代表。其修饰器(OpenClawProComponents.swift)逻辑如下:
- iOS 26 可用时:
prominent为 true 走.buttonStyle(.glassProminent),否则走.buttonStyle(.glass),配合.tint(_:)设定着色; - iOS 18 回退:
prominent为 true 走.buttonStyle(.borderedProminent),否则走.buttonStyle(.bordered)。
文档明确要求回退路径必须保持相同的 label、action、tint 含义、可访问性以及近似的触控目标。另外,所有新增的 iOS 26 API 都必须包在#available(iOS 26.0, *)之后,这正是该修饰器中if #available(iOS 26.0, *)分支存在的意义。类似的还有OpenClawGlassSurfaceModifier(同文件 L129-L141):iOS 26 用.glassEffect(.regular, in: .rect(cornerRadius:)),iOS 18 用.regularMaterial背景近似模拟。
Liquid Glass 规则:克制使用与性能边界
文档对 Liquid Glass 的使用给出了非常明确的纪律:
- 用
openClawGlassButton承载主操作与导航相邻控件;每个区域只允许一个prominent主操作。 - 相邻的玻璃控件用
OpenClawGlassControlGroup包起来,让系统以容器为单位统一渲染玻璃效果,而不是逐个控件独立做玻璃(这也是性能优化的关键点)。 - 共享侧边栏展示控件与 Chat 操作为例外:它们是「无背景的 header 例外」,直接保留 44pt 触控目标,不再为字形额外画圆形背景。
反例则被明令禁止:
Do not place Liquid Glass behind reading content, forms, metrics, or every card in a scroll view. Excess glass weakens hierarchy, increases rendering cost, and competes with the sidebar and navigation chrome.
翻译成工程语言就是:阅读内容、表单、指标、滚动视图中每一张卡片后面都不要放玻璃。玻璃泛滥会削弱层级、提高渲染成本,并和侧边栏与导航镀铬层争抢视觉焦点。
源码印证了这一纪律:ProCard通过proPanelSurface使用普通的圆角填充 + 描边(见 OpenClawProComponents.swift 的ProPanelBackground),刻意与玻璃控件划清界限;而回归测试 RootTabsSidebarRegressionTests.swift 甚至直接断言侧边栏控制图标中不出现.glassEffect(与Circle()背景。
黑色侧边栏与抽屉布局:从「常驻栏」到「推入抽屉」
文档规定根导航在所有设备形态(idiom)上使用单一黑色侧边栏,并根据布局宽度决定形态:
- 宽屏横屏(wide landscape):持久常驻的侧边栏;
- 手机、竖屏、窄布局(phones, portrait, narrow layouts):推入式(push-reveal)抽屉层,位于内容背后。
实现层由 RootTabs.swift 承载。其中sidebarSplitContent(L155-L205)通过GeometryReader计算布局容器尺寸,调用shouldUseSidebarDrawer(containerSize:)判定是否进入抽屉模式,再分别渲染sidebarNavigationSplitContent(L222-L239,常驻栏 + 内容区)或sidebarDrawerContent(L241-L255,抽屉 + 内容卡)。布局状态由updateSidebarLayout(containerSize:force:)统一管理,且带didResolveSidebarLayout防抖,避免键盘安全区变化被误判为窗口/方向变化而销毁聚焦的详情子树。
抽屉本体 RootSidebarDrawer.swift 的实现细节非常值得借鉴:
- 内容卡是「一张全出血圆角卡片」:
contentCard(L74-L93)将详情内容裁成连续圆角形状(cornerRadius = 28),在抽屉展开时向右偏移露出侧边栏,并叠加描边(hairline.opacity(progress))与OpenClawProBackground背景; - 手势状态放在稳定的壳层:
@GestureState(resetTransaction:)挂在抽屉外层,配合.simultaneousGesture与DragSession记录拖拽方向,避免「一次返回滑动既关抽屉又触发 pop」的双重响应问题(L56-L64、L118 起);DragDisposition区分opening / closing / rejected; - Reduce Motion 兼容:开启系统减弱动态效果时禁用拖拽手势(
isEnabled: !self.reduceMotion),抽屉改为纯显隐动画; - 边缘手势宽度 44pt(
edgeGestureWidth),顶部排除区也是 44pt,与触控目标规范保持一致。
相关的布局决策均有测试覆盖:RootTabsPresentationTests.swift 中验证了「iPad 竖屏用隐藏抽屉侧边栏」(L486 起)、「抽屉宽度不超出屏幕」(L548 起)、「窄横屏保持抽屉模式」(L943 起)等行为;RootSidebarDrawerGestureTests.swift 则覆盖了抽屉拖拽的开启/关闭方向判定。
侧边栏色板:深浅外观下保持「黑」
OpenClawSidebarPalette(OpenClawSidebarPalette.swift)为侧边栏定义了固定色板:亮色外观下背景为0xFAFAFA,暗色外观下为0x000000,通过adaptive(light:dark:)辅助函数按userInterfaceStyle生成自适应色。textStrong与text均为0x171717(亮)/0xEDEDED(暗),muted固定0x8F8F8F。它保证侧边栏在任何 App 外观下都保持深色视觉(暗色模式下接近纯黑),与内容区的systemGroupedBackground形成明确区分。注意:源码注释提到抽屉本身仍跟随 App 外观(「owner decision superseding always-dark」),即「黑栏」承诺主要落在侧边栏表面。
Review Checklist:把设计纪律变成可执行的验收清单
文档附带的审查清单是每个改动合入前应当逐条走查的:
- 原生容器优先:存在原生容器或控件的地方是否使用了原生实现(
List、Form、toolbar、sheet 等)? - 共享 Token:是否使用了共享间距与圆角 Token(
OpenClawProMetric/OpenClawSpacing/OpenClawRadius)? - 单一主操作:每个区域是否只有一个明确的主操作?
- 语义色独立:语义色是否与装饰性颜色解耦(状态色不承担装饰职能)?
- 四种形态验证:亮色/暗色模式、Dynamic Type、紧凑手机布局下是否都正常?
- 双系统验证:在模拟器中验证 iOS 26 外观,同时保留并验证 iOS 18 回退路径(对应
#available(iOS 26.0, *)分支)。 - 视觉变更留证:为视觉变更补充 before/after 匹配证据(仓库中 OpenClawSnapshotUITests.swift 即承担快照类 UI 验证)。
这套清单本质上把前面所有的设计原则压缩成了可机械执行的自检项,尤其第 6 条呼应了仓库的工程现实:deploymentTarget是 iOS 18.0,但 Xcode 版本已是 26.0,任何新系统 API 都必须自带回退,否则会直接破坏低版本用户的使用体验。
源码导航:快速定位相关实现
如果你要基于这套设计系统继续开发或参考,建议按以下路径深入:
- 设计系统总纲:apps/ios/DESIGN.md
- 共享组件与 Token:apps/ios/Sources/Design/OpenClawProComponents.swift
- 侧边栏色板:apps/ios/Sources/Design/OpenClawSidebarPalette.swift
- 根导航与布局决策:apps/ios/Sources/RootTabs.swift
- 抽屉实现:apps/ios/Sources/RootSidebarDrawer.swift
- 侧边栏视图:apps/ios/Sources/RootSidebar.swift
- 回归测试:apps/ios/Tests/RootTabsSidebarRegressionTests.swift、apps/ios/Tests/RootTabsPresentationTests.swift、apps/ios/Tests/RootSidebarDrawerGestureTests.swift
总结
OpenClaw iOS 设计系统给出的答案可以浓缩为三点:以 iOS 26 原生设计语言为方向、以 iOS 18 为兼容基线、以「系统结构 + 克制玻璃 + 语义色 + 可访问性」为执行纪律。OpenClawProMetric统一了几何尺度,openClawGlassButton示范了新旧系统双路径的最简写法,RootSidebarDrawer展示了推入式侧边栏在手势、圆角与 Reduce Motion 上的完整考量,而 Review Checklist 则让每一项原则都能在代码评审中被逐条验证。对任何需要在「新系统特性」与「旧系统兼容」之间保持平衡的 SwiftUI 项目来说,这套设计系统都是一份可以直接复用的工程模板。
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考