Files

11 KiB

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. 官方资料