Files
win_ui_ux_design_skill/references/adapter-gio.md
T

136 lines
11 KiB
Markdown

# Go Gio Windows 桌面适配指南
## 目录
1. 版本与适用边界
2. 即时模式架构与状态
3. Windows 视觉与布局
4. 核心交互模式映射
5. 文件、异步与长任务
6. 键盘、焦点与无障碍
7. 构建、测试与交付
8. 常见反模式
9. 官方资料
## 1. 版本与适用边界
生成代码前读取 `go.mod`、`go.sum`、入口文件和实际使用的 `gioui.org` 子包,确认 Go、Gio 与扩展包的准确版本。Gio 模块仍是 v1 之前版本,次版本可能包含不兼容变化;应固定已验证版本,并以该版本的包文档和示例为准。
Gio 适合需要 Go 单一技术栈、自绘界面、跨平台渲染和高度定制交互的桌面应用。它不会自动提供完整的 Windows Fluent 控件集,也没有与 WinUI `DataGrid`、`TabView`、`ContentDialog` 或 Mica 一一对应的内置组件。选择 Gio 意味着项目需要明确承担复合控件的状态、输入、焦点、语义、主题和测试成本。
## 2. 即时模式架构与状态
Gio 使用即时模式:应用读取窗口事件、更新持久状态,再在每个 `FrameEvent` 中布局并绘制当前帧。不能依赖上一帧留下的控件对象树。
- `widget.Clickable`、`widget.Editor`、列表位置、标签选择、筛选值和弹层状态等必须由页面或组件结构体长期持有,不能在每一帧的布局函数中重新创建。
- 领域数据与 UI 交互状态分离。记录以稳定 ID 识别,不以可见标题、排序后的行号或循环索引作为业务身份。
- 布局函数应接近纯函数:读取状态、消费本帧输入、产生操作;文件、网络、数据库和昂贵计算放在布局循环之外。
- 将导入、刷新、生成、更新、提交等动作建模为集中命令,统一管理启用条件、执行中、防重复、取消、结果和错误,不要只散落在 `Clicked()` 分支中。
- 通过显式页面状态描述空闲、加载、内容、空、筛选后为空、错误、离线/过期、权限拒绝和部分结果。
窗口事件循环必须处理 `FrameEvent` 与 `DestroyEvent`,并保证每个帧事件都完成提交。后台结果到达时更新线程安全的应用状态并调用 `Window.Invalidate()` 请求重绘;不要用忙循环持续刷新。
## 3. Windows 视觉与布局
`widget/material` 提供 Material Design 主题和样式,它不是 Windows Fluent 设计系统。Windows 项目应在 Gio 上建立一层薄的设计适配:集中定义语义颜色、字体、字号、间距、圆角、描边、阴影、状态层、图标和动效,再用这些 Token 组合组件。不要在各页面直接散布颜色和尺寸常量。
- Windows 字体优先使用系统可用的 Segoe UI Variable/Segoe UI,并准备缺失时的回退;验证中文字体与混排。
- 保留系统装饰窗口和标准关闭、最大化、最小化、调整大小行为。不要仅为“像 WinUI”而自制整套非客户区。
- 不宣称 Gio 内置原生 Mica/Acrylic。只有在隔离的 Windows 原生适配经过版本、性能、高对比度和失效测试后才启用,并始终提供纯色主题表面回退。
- 以 `layout.Context` 的 `Constraints` 决定紧凑、中等和宽布局,用 `layout.Flex`、`layout.Stack`、`layout.Inset` 和 `layout.List` 组合,不按全屏分辨率或固定像素坐标布局。
- 在断点切换时保留输入、焦点、选择、勾选、筛选、滚动、展开、任务和未保存状态。
主题至少覆盖浅色、深色、高对比度或可访问的强对比回退,并验证系统强调色不可用、透明效果关闭和远程桌面等场景。颜色不能成为错误、选择或状态的唯一线索。
## 4. 核心交互模式映射
### 导航与标签
Gio 没有内置完整 `NavigationView`/`TabView` 体验。用稳定页面 ID 维护顶级导航,用稳定标签 ID 维护文档工作区,并自行定义:键盘切换、焦点返回、关闭、重排、溢出、未保存确认、任务归属和状态恢复。标签标题只是显示文本,不能作为身份。
### 数据表格
大型表格使用 `layout.List` 或经过测量的自定义虚拟化行布局,只绘制可见区域,避免为每个单元格长期持有昂贵对象。列宽、表头、滚动、固定列和编辑行为需形成单独组件契约。
必须分别建模:
- 当前行/单元格;
- 键盘焦点;
- 选择集;
- 勾选集。
指针命中后先解析稳定记录 ID,再处理单击选择、双击默认操作、右键上下文目标、复选框和行内按钮。双击不能额外执行一次单击的破坏性动作;复选框或行内按钮消费事件后不能继续触发行默认操作。Ctrl/Shift 多选、Space 切换、Enter 调用、上下文菜单键或 Shift+F10 都要有明确规则。排序和筛选后按 ID 恢复有效状态,并向用户说明被筛选隐藏的勾选项。
### 表单
用持久的 `widget.Editor`、布尔/枚举选择状态和应用层字段模型构造表单。每个字段定义标签、说明、必填、格式、领域规则、验证时机、错误位置和提交模式。提交失败保留输入并将焦点移到首个错误;异步验证以请求 ID 或取消机制忽略旧结果。占位文本不能代替字段标签。
### 对话框、反馈与任务
Gio 中的对话框、浮层、信息条通常需要应用自行组合。模态层必须限制背景交互、建立正确绘制层级、将焦点移入、支持 Escape/关闭规则,并在关闭后将焦点返回触发点。只有不可逆、高代价或没有安全默认值的决定才阻塞确认。
普通成功使用内联状态或非阻塞通知;可恢复错误保留上下文并提供重试;长任务在页面内显示阶段、进度、取消和结果。不要为每次生成、更新或提交统一弹出成功对话框。
### 多 Tab 数据工作台
所有工作标签复用同一页面骨架:标题与说明、导入/配置/刷新等顶部前置命令、来源与校验状态、可伸展表格主区、选择摘要,以及生成/更新/提交等底部完成命令。每个命令显式绑定作用域、前置条件、风险、可逆性、确认策略和完成反馈。
## 5. 文件、异步与长任务
文件选择可使用 `gioui.org/x/explorer`,但必须遵循其窗口生命周期:每个窗口创建对应 `Explorer`,将窗口事件传给 `ListenEvents`,并从独立 goroutine 调用阻塞的 `ChooseFile`、`ChooseFiles` 或 `CreateFile`。返回句柄按 `io.Reader`、`io.Writer` 或相关接口使用,不要假设一定是 `*os.File` 或具有普通文件路径。
- goroutine 不直接无同步地修改布局正在读取的复合状态;通过 channel、互斥保护的结果或项目统一状态容器交接。
- I/O、网络、数据库与计算任务不得阻塞窗口事件循环。
- 长任务使用 `context.Context` 或等价取消协议,携带任务 ID,并在窗口关闭、标签关闭或新请求替代旧请求后丢弃过期结果。
- 任务提交阶段要定义幂等性;不能幂等时在进行中禁用重复命令并清楚显示原因。
- 后台状态改变后调用 `Window.Invalidate()`,不要依赖用户移动鼠标才看到结果。
## 6. 键盘、焦点与无障碍
用 `key.Filter` 声明需要接收的键事件,用 `key.FocusCmd` 请求焦点,并处理焦点进入、离开和方向移动。快捷键的作用域必须清晰;重复操作提供 Windows 常用快捷键或可发现的替代路径。所有仅右键、悬停、拖拽或触控可达的功能都需要键盘路径。
使用 `io/semantic` 为自定义组件公开合适的类别、标签、说明、启用、选择及其他状态。复合表格、标签、对话框和自绘输入承担比标准控件更高的语义责任;代码中存在语义操作不代表屏幕阅读器体验已正确,必须用 Windows Narrator 和无障碍检查工具执行真实任务测试。
焦点指示必须在浅色、深色与强对比背景上清晰;弹层打开和关闭、标签切换、删除当前记录、筛选后当前项消失时都要定义焦点落点。状态变化与错误需要可感知的文本和语义反馈,不能只改变颜色或播放动画。
## 7. 构建、测试与交付
Windows GUI 发布构建可按项目需要使用 `-ldflags="-H windowsgui"` 隐藏控制台,但开发构建应保留可诊断日志。锁定 Go/Gio/扩展模块版本,保存可复现构建命令,并在干净 Windows 环境验证产物、资源、字体、图标与文件选择器。
最低测试矩阵包括:最低支持 Windows 与当前 Windows 11;紧凑/中等/宽窗口、贴靠、最大化和多显示器;100%/125%/150%/200% 缩放;浅色、深色、强对比回退;键盘、鼠标及声明支持的触控;Narrator;空、真实、超大、错误、权限拒绝和慢任务数据;窗口/标签关闭、取消、重试和恢复。
交付前确认:
- [ ] 所有持久 Widget 状态未在帧布局中意外重建。
- [ ] 页面、标签和记录使用稳定 ID,而非索引或标题。
- [ ] 大型列表/表格只布局可见内容,并以真实数据测量。
- [ ] 后台任务不阻塞事件循环,状态同步无数据竞争,结果到达会触发重绘。
- [ ] 键盘、焦点、语义、对话框和上下文菜单已用真实辅助技术验证。
- [ ] Windows 视觉层使用集中 Token,且有纯色和强对比回退。
- [ ] 依赖版本、构建命令和自定义复合控件责任已记录。
## 8. 常见反模式
- 每帧重新创建 `widget.Clickable`、`widget.Editor` 或列表状态,导致输入和焦点丢失。
- 把 `widget/material` 的默认外观直接称为 Windows Fluent。
- 在事件循环中执行阻塞 I/O,或用持续重绘掩盖状态同步问题。
- 用排序后行号保存勾选或选择,导致筛选后作用于错误记录。
- 自绘表格、标签或弹层,却没有键盘、焦点、语义和屏幕阅读器测试。
- 假设 `x/explorer` 返回本地路径或 `*os.File`,或者在帧处理 goroutine 中调用其阻塞选择方法。
- 为视觉效果移除系统窗口能力,或把未经验证的 Windows 私有 API 变成必需依赖。
## 9. 官方资料
- [Gio 架构](https://gioui.org/doc/architecture)
- [Gio Widget 架构](https://gioui.org/doc/architecture/widget)
- [窗口事件与重绘](https://gioui.org/doc/architecture/window)
- [输入处理](https://gioui.org/doc/architecture/input)
- [布局系统](https://gioui.org/doc/architecture/layout)
- [layout 包](https://pkg.go.dev/gioui.org/layout)
- [widget 包](https://pkg.go.dev/gioui.org/widget)
- [Material 组件包](https://pkg.go.dev/gioui.org/widget/material)
- [键盘输入包](https://pkg.go.dev/gioui.org/io/key)
- [语义无障碍包](https://pkg.go.dev/gioui.org/io/semantic)
- [窗口 app 包](https://pkg.go.dev/gioui.org/app)
- [文件选择 explorer 包](https://pkg.go.dev/gioui.org/x/explorer)