ui_lite 组件层详解:frameworks/components 全解析
一、组件分类:普通组件 vs 容器组件
| 类别 | 定义 | 典型成员 | 关键限制 |
|---|---|---|---|
| 普通组件(叶子) | 只干自己的事,不能挂子节点 | UIButton、UILabel、UIImageView、UICanvas、UIBoxProgress、UICircleProgress、UIEditText、UICheckbox | 继承自 UIView,Add() 无意义 |
| 容器组件 | 持有子节点列表,负责排布 + 转发事件 + 转发绘制 | UIViewGroup、UIScrollView、UIList、UISwipeView、UIDialog、UIPicker | 继承自 UIViewGroup,遍历顺序决定 Z 序和事件优先级 |
UIView(所有组件的根)
├── 坐标/尺寸/可见性/点击监听/绘制入口/标脏(Invalidata)
│
├── UIButton ──┬── UILabelButton(文字按钮)
│ └── UIRepeatButton(长按连发)
├── UILabel
├── UIImageView ──┬── UIImageAnimatorView(帧动画)
│ └── UITextureMapper(仿射变换贴图)
├── UICanvas(自绘留白区)
├── UIAbstractProgress ──┬── UIBoxProgress(矩形进度条)
│ └── UICircleProgress(环形进度)
├── UIArcLabel(弧形旋转文字)
└── UIViewGroup(容器基类)
├── UIScrollView(滚动)──┬── UIList(列表,带复用)
│ └── UISwipeView(分页滑动)
├── UIDialog(弹窗)
├── UIPicker(选择器)
└── RootView(根视图,渲染调度单例)
二、基础控件组
2.1 UILabel:最简单的叶子
- 负责文本测量与绘制(走
font模块,受字库裁剪影响极大)。 - 坑:小内存设备字库常被裁剪,缺字会显示成方块,不是 bug 是配置问题;长文本不换行会越界,需手动截断或自己算行高。
2.2 UIButton / UILabelButton / UIRepeatButton
| 类 | 定位 | 关键接口 |
|---|---|---|
UIButton | 图片态按钮,支持多状态样式 | SetImageSrc(default, triggered)、SetStyle(ButtonState)、Enable()/Disable() |
UILabelButton | 文字按钮(UIButton + UILabel 组合语义) | 设置文本、按下态颜色 |
UIRepeatButton | 长按连续触发(如加减计数器、长按快进) | 内部持定时器,按住周期发事件 |
实现要点:按钮的本质是 状态机(NORMAL / PRESSED / DISABLED)+ 命中判定 + 抬起时触发。写自定义可交互控件就照这个模板抄。
2.3 UIImageView:图片叶子
- 依赖
imgdecode解码,格式支持 PNG/JPEG/ARGB8888/RGB565 等(编译期宏开关控制)。 - 两个高频坑:
- JPEG 大图在低内存设备上解码即 OOM → 必须做缩图解码或预生成小图;
- PNG 含 alpha 的图反复绘制 → 考虑缓存成离屏 bitmap(如果后端支持)。
三、滚动容器组:UIScrollView / UIList / UISwipeView
这是整个模块最复杂、最容易写出性能事故的一组。
3.1 UIScrollView:滚动的最小闭环
职责:维护一个可拖动的内容区,比可视区大,通过偏移量决定画哪一段。
contentSize > viewportSize → 可滚动
drag 阶段:记录起始点 + 累计 delta → SetScrollOffset → Invalidate()
fling 阶段:初速度 → 衰减曲线 → 逐帧 tick(走 Animator)→ 停
边界:到达边缘回弹/阻尼
必查清单:
- ✅ 是否设置了正确的 content size(设错 = 滚不动或滚出空白)
- ✅ 拖动时是否只标脏新旧两个区域(很多实现图省事全屏 Invalidate)
- ✅ fling 动画是否在不可见时停掉(页面隐藏要主动 stop)
- ✅ 子控件超出是否被 clip(否则滚动时残影留在屏幕上)
3.2 UIList:列表 + 回收复用
UIList 相比 UIScrollView 多的唯一一件事就是回收复用——这也是它存在的理由。
数据项 N 个,但屏幕上只显示 K 个(K << N)
→ 只创建 K+缓冲 个 item 实例
→ 滑动时,移出屏幕的 item 被「回收」,填入新数据,挪到另一端
开发纪律:
- item 必须尺寸固定或可预计算(轻量系统没有复杂的自适应测量)。
- 复用时必须重置所有状态(选中态、颜色、文本),否则旧状态会泄露到新数据上——这是列表「错乱」的第一大原因。
- 不要在 item 里持有外部对象的裸指针,回收后悬空。
3.3 UISwipeView:分页滑动(轮播/Tab 页)
官方接口(南向开发常用):
表格
| 方法 | 作用 |
|---|---|
UISwipeView(HORIZONTAL / VERTICAL) | 构造指定方向 |
Add(view) | 按添加顺序自动水平/垂直排列 |
SetCurrentPage(index) / GetCurrentPage() | 切页 |
GetCurrentView() / GetViewByIndex(i) | 取页 |
SetOnSwipeListener(cb) | 翻页回调 |
SetAnimatorTime(ms) | 翻页动画时长 |
SetLoopState(bool) | 是否循环 |
特性:滑动结束后当前页居中对齐(snap to page)。
坑:开启 loop 时首尾衔接的实现质量参差不齐,部分版本会出现首尾空白页,需实测;页内如果是 UIList,嵌套滚动冲突要自己在 listener 里做方向裁决。
四、输入控件:UIEditText / UICheckbox
UIEditText:文本输入,涉及焦点管理、软键盘/物理键盘输入、光标闪烁(逐帧动画)、文本溢出滚动。焦点是全局唯一的,切焦点时要记得把旧编辑框的键盘收起、光标停掉。UICheckbox:选中态切换 + 图标切换。典型「状态驱动绘制」的最小教学案例:checked_变 →Invalidate()→Draw里根据状态选图标。
共同点:它们是有「内部状态」的控件,状态变了必须标脏。记住这个模式,你自己写的控件也一样。
五、图表与画布:UICanvas / UIChart
5.1 UICanvas:自绘的「白盒」
class MyCanvas : public UICanvas {
void Draw(const Rect& area) override {
DrawLine(...); DrawRect(...); DrawText(...); // 走 draw 原语
}
};
适用:仪表盘、波形、自定义进度、签名板。
不适用:复杂交互控件(那就该继承 UIView/UIViewGroup 自己做完整控件)。
5.2 UIChart 族:折线 / 柱状 / 坐标轴
UIChart(图表容器,UIViewGroup)
├── UIAxis / UIXAxis / UIYAxis ← 坐标轴、刻度、标签
├── UIChartPolyline ← 折线图
└── UIChartPillar ← 柱状图
现实提醒:这组组件能力非常基础(少量序列、无缩放交互、无大数据量优化)。数据点多起来必卡,因为每帧重绘全部图元。真要做大点数实时曲线:自己写环形 buffer + 只重绘新增段 + 降采样。
六、进度指示:UIAbstractProgress → UIBoxProgress / UICircleProgress
UIAbstractProgress(抽象进度,存 value/min/max/direction)
├── UIBoxProgress 矩形条(横/竖)
└── UICircleProgress 环形进度(圆弧绘制)
UIArcLabel 沿弧排列的文字(表盘刻度文字常用)
共性坑:进度从 30% → 31% 时,只标脏变化那一段弧/那一段矩形,不要整控件重绘。动画型进度(平滑过渡)要走 animator,并且页面退出时必须停掉,否则后台空转耗电。
七、弹窗与选择器:UIDialog / UIPicker
UIDialog:本质是一个覆盖在根视图上的半透明遮罩 + 居中容器,带模态事件拦截(背景点击关闭 / 拦截下方事件)。实现要点:弹出时要把下方事件拦截住,否则弹窗下面的按钮还能点——这是最常见的弹窗 bug。UIPicker:多列滚动选择器,内部通常是多个UISwipeView/UIList组合 + 中间高亮条。列之间联动(省市区三级联动)时,注意别在回调里同步刷新另一列导致递归刷新。
八、变换与帧动画:UITextureMapper / UIImageAnimatorView
| 类 | 能力 | 说明 |
|---|---|---|
UIImageAnimatorView | 序列帧播放(从 UIImageView 继承) | 依赖 animator 模块逐帧切换 src;帧数多、图大 → 内存爆炸,建议预合成或使用小尺寸序列帧 |
UITextureMapper | 图片的仿射变换(旋转/缩放/平移贴图) | 用于表盘指针、旋钮、仪表盘指针这类「绕点旋转」的场景 |
表盘开发的经典组合:UITextureMapper(指针旋转)+ UIArcLabel(刻度数字)+ UICircleProgress(进度环)。这三者同屏且都在逐帧动 → 务必确认它们的脏区都是局部小矩形,否则一帧下来全屏重绘,低端芯片直接 10fps。
九、边界:什么不该在 components 里做
表格
| 想做 | 正确归属 |
|---|---|
| 算布局、自适应排布 | layout/(FlexLayout / GridLayout / ListLayout) |
| 逐帧属性动画 | animator/(AnimatorManager) |
| 画一条线/一个圆/一段文字 | draw/ 原语,不要自己在组件里操作 pixel buffer |
| 响应触摸/按键 | events/,组件只接回调 |
| 创建窗口、上屏合成 | window/ + window_manager_lite |
| 跨进程事件、状态同步 | 上层应用框架,不是 ui_lite |
更多推荐

所有评论(0)