MaixPy-UI-Lib:我参与构建的嵌入式 UI 组件体系
MaixPy-UI-Lib 是我基于 aristorechina/MaixPy-UI-Lib 参与继续构建的轻量级 UI 库。我的工作覆盖组件组织、分辨率适配、页面系统、包结构、示例和文档,其中多项修改通过 PR #2、PR #4 和 PR #7 合并到上游。
这个仓库要解决什么问题
MaixPy 设备可以直接在图像上绘制界面,但项目一复杂,按钮命中、滑块状态、页面切换和不同分辨率会反复出现。如果每个应用都在主循环里手写坐标判断,UI 代码很快会和视觉算法、相机处理混在一起。
这个仓库要提供一套适合嵌入式环境的基础 UI:组件足够轻,能够直接绘制到图像;输入事件由管理器统一分发;多页面应用有清楚的进入、退出和返回规则;在不同屏幕尺寸上还能复用同一套设计坐标。
我采用的整体方案
我参与把代码整理成标准 src/maixpy_ui 包。components 下分别放按钮、滑块、开关、复选框和单选框,每类组件都有对应管理器;core/resolution_adapter.py 负责设计分辨率到设备分辨率的换算;core/ui_manager.py 定义 Page 与 UIManager,组织多页面应用。
组件只处理自身绘制、触摸命中和状态变化,管理器负责保存组件集合与分发输入。页面则作为更高一层容器,拥有父子关系和生命周期回调。这个层次让我可以在一个页面内组合多种组件,又不会让组件知道整个应用如何导航。
包入口统一导出常用类,仓库同时保留基础示例、颜色阈值调节和复杂菜单示例。README 按组件给出初始化、回调、主循环和 API,CHANGELOG 记录版本变化,最终整理到 2.4。
组件和分辨率怎么处理
Button、Slider、Switch、Checkbox 与 RadioButton 都围绕同一种运行方式设计:应用创建组件和回调,把触摸坐标交给管理器,再把组件绘制到当前图像。状态变化通过回调传给业务代码,不让业务层直接修改组件内部细节。
不同 Maix 设备的屏幕尺寸不一样。ResolutionAdapter 保存设计基准分辨率与实际分辨率,统一缩放位置、尺寸和字体参数。应用可以按 640x480 设计,再在目标设备上转换,不必到处散落倍率计算。
嵌入式环境资源有限,所以这套库没有引入复杂布局引擎。它选择明确坐标加统一适配,换取更可控的绘制成本。
页面系统怎么构建
Page 不是一个简单的名称,它保存父页面、子页面和 UIManager 引用,还定义 on_enter、on_exit、子页面进入退出与 update 生命周期。页面可以查询根节点、深度和路径,也能按路径寻找目标页面。
UIManager 维护根页面和当前页面,负责进入子页、返回父页、按路径跨层跳转和移除页面。我补充 remove_page 时,也处理当前页面被删除后的落点和父子关系,避免导航仍指向已经不存在的对象。
树形结构适合表达菜单层级,但真实使用中还会跨层跳转。颜色阈值 UI 和复杂菜单示例就是用来验证这些情况:页面进出时状态是否保留,错误路径怎样处理,连续返回能否到达预期页面。
开源交付不只是一份代码
其中一次核心调整约新增 356 行、删除 48 行,但最终贡献还包括包目录、两个大型示例、README、CHANGELOG 和版本号。它们和实现一起参与了这套库的构建。
提交给上游时,我需要考虑原有接口、命名一致性和用户如何迁移。一个功能在我的设备上运行,不代表它已经适合公共库。维护者要能审阅,旧用户要知道变化,新用户也要有可以直接运行的入口。
截至这次提交的复盘
当前仓库已经形成组件层、输入管理层、分辨率适配层和页面导航层,能够支撑比单页 Demo 更完整的 MaixPy 应用。
接下来仍需要更多设备与分辨率测试,也可以继续统一各组件管理器的接口,减少使用者在不同组件之间切换时的认知差异。页面转场和焦点管理目前保持轻量,也要避免为了功能完整引入超出设备承受范围的复杂度。
这次贡献让我完成的不是某一个控件,而是把一组控件组织成可以复用、安装、导航和阅读的库。对开源项目来说,整体结构、示例和文档同样属于代码设计的一部分。




