4. UI基础组件(上):Box、TextArea、Button、Image的使用与属性配置
好,咱们正式开始动手搭界面了。说实话,TouchGFX里组件不少,但真正天天打交道的,就是今天要讲的这四个:Box、TextArea、Button、Image。你想想看,一个嵌入式设备的屏幕,无非就是背景、文字、按钮、图标这四样东西。把这四个玩透了,后面那些花哨的容器、滑动列表、图表,学起来就快得多。
我个人习惯,每接触一个新组件,先看它“能干什么”,再看它“属性怎么调”,最后看“实际项目里怎么用”。咱们今天就按这个路子走。
核心认知:这四个组件是TouchGFX的“原子级”基础。Box负责填充和背景,TextArea负责文字输出,Button负责交互响应,Image负责图形展示。它们之间没有继承关系,但可以组合使用。
4.1 Box(矩形框)—— 最朴素的填充组件
Box说白了就是一个纯色矩形。没有边框,没有圆角,没有渐变,就是一块颜色。你可能觉得这玩意儿太简单了,但我在项目里发现,很多人恰恰因为觉得它简单,反而用错了地方。
典型用途:
- 屏幕背景色填充
- 分割线、状态条
- 进度条的底色块
- 遮罩层(配合透明度)
属性配置要点:
| 属性 | 说明 | 我的建议 |
|---|---|---|
| Color | 填充颜色,24位RGB | 尽量用调色板里的命名色,别手写十六进制 |
| Alpha | 透明度,0-255 | 做遮罩时常用128左右,全透明用0 |
| Position & Size | 位置和尺寸 | 建议用百分比布局,别写死像素 |
小技巧:Box的Alpha属性是独立于整个屏幕的透明度的。我曾经做一个夜间模式切换,就是用两个Box叠在一起,上层Box的Alpha从0渐变到180,效果非常平滑,而且不耗额外内存。
嗯,这里要注意一点:Box没有点击事件。它就是个“哑巴”组件。如果你想做一个可点击的矩形区域,请用Button,或者用Box+手势区域组合。我见过有人试图给Box加回调函数,折腾半天发现不行——方向错了。
4.2 TextArea(文本区域)—— 显示文字的正确姿势
TextArea是TouchGFX里最常用的文字组件。你可能会问,为什么不直接用Button显示文字?因为TextArea专门为文字渲染做了优化,支持换行、对齐、字体切换,而且不产生任何交互开销。
核心属性:
- TypedText: 指向一个预先定义好的文本资源(在Texts文件夹里配)
- Wildcard: 通配符,用于动态显示数字、变量值
- Alignment: 左对齐、居中、右对齐
- Lines: 最大行数,超出部分截断
避坑指南:我曾经在项目里犯过一个低级错误——直接在TextArea的构造函数里写中文。结果编译通过,但屏幕上一片空白。为什么?因为TouchGFX的文本渲染依赖字体文件,你必须先在Assets/Fonts里生成包含中文字符的字体,然后在Texts里定义对应的TypedText。直接写字符串是没用的。
动态更新文本的代码示例:
// 在视图类中更新TextArea内容
// 假设有一个TextArea名为 textAreaValue
// 和一个通配符缓冲区 wildcardBuffer
Unicode::snprintf(wildcardBuffer, BUFFER_SIZE, "%d", sensorValue);
textAreaValue.setWildcard(wildcardBuffer);
textAreaValue.invalidate(); // 强制重绘
这段代码我几乎每个项目都会写。注意invalidate()这行,很多人忘了调,结果数据变了但界面没刷新。说白了,TouchGFX的渲染机制是“脏矩形”模式——你告诉它哪里变了,它才重绘哪里。
4.3 Button(按钮)—— 交互的起点
Button是用户和系统交互的桥梁。TouchGFX提供了好几种按钮变体,但最常用的是Button(图片按钮)和TextButton(文字按钮)。
按钮类型对比:
| 类型 | 触发方式 | 状态图 | 适用场景 |
|---|---|---|---|
| Button | 点击释放时触发 | 按下/释放两张图片 | 图标按钮、自定义样式 |
| TextButton | 同上 | 按下/释放两种文字样式 | 菜单项、表单按钮 |
| ToggleButton | 点击切换状态 | 选中/未选中两张图片 | 开关、模式切换 |
| RepeatButton | 按住持续触发 | 同Button | 音量加减、数值微调 |
我个人最常用的是Button,因为它最灵活。你给它两张图——一张正常态,一张按下态——它就能工作。但要注意图片尺寸必须一致,否则会拉伸变形。我刚开始做的时候就被这个坑过,按下去按钮突然变大了,用户体验极差。
绑定回调函数:
// 在视图的setupScreen()中绑定
buttonConfirm.setAction(buttonConfirmHandler);
// 回调函数实现
void MyView::buttonConfirmHandler(const AbstractButton& src) {
// 处理点击事件
if (&src == &buttonConfirm) {
// 执行确认逻辑
executeConfirm();
}
}
经验之谈:回调函数里不要做耗时操作。我曾经在一个按钮回调里直接写Flash写入操作,结果界面卡死了一秒多。正确的做法是:在回调里设置一个标志位,然后在tick()函数里处理耗时任务。这样界面始终流畅。
4.4 Image(图片)—— 让界面活起来
Image组件就是用来显示图片的。它支持PNG、JPG、BMP等格式,但实际项目中我几乎只用PNG——因为支持透明通道,而且TouchGFX对PNG的渲染效率最高。
图片资源管理:
- 所有图片必须导入到Assets/Images文件夹
- TouchGFX Designer会自动生成对应的BitmapId
- 图片尺寸最好是2的幂次(如64x64、128x128),但不是强制
动态切换图片:
// 切换图片显示
imageStatus.setBitmap(Bitmap(BITMAP_ICON_WIFI_ON_ID));
imageStatus.invalidate();
// 或者用缩放模式
imageStatus.setScalingMode(Image::FIT_ZOOM); // 保持比例缩放
嗯,这里有个细节:setScalingMode有几种模式,FIT_ZOOM是保持比例缩放,FILL是拉伸填充,NONE是原尺寸。我建议图标类用NONE,背景图用FILL,产品图用FIT_ZOOM。你想想看,一个圆形的Logo被拉伸成扁的,多难看。
内存警告:TouchGFX的图片是直接解码到内存的。一张800x480的24位PNG,解压后占用800*480*3 ≈ 1.1MB内存。如果你的MCU只有512KB RAM,那就得用L8格式(8位索引色)或者RGB565(16位色)来压缩。我曾在资源紧张的项目里把所有图片转成L8格式,内存占用直接砍半。
4.5 组件组合实战:一个简单的状态卡片
光讲理论没意思,咱们来组合一下。假设我们要做一个设备状态卡片,包含背景、标题、状态图标、操作按钮。用今天学的四个组件就能搞定。
布局思路:
- Box作为卡片背景,白色半透明,圆角效果用图片模拟
- TextArea显示“设备状态”标题
- Image显示在线/离线图标
- Button作为“刷新”按钮
你看,没有用到任何高级容器,四个基础组件就搭出了一个可用的UI模块。实际项目中,这种组合方式占了界面元素的80%以上。
核心原则:能用基础组件解决的问题,就不要引入复杂容器。基础组件渲染开销低、内存占用小、调试方便。我见过有人为了一个圆角效果,硬是用了Container+Box+Painter,其实一张圆角PNG图片就解决了。
这张图把今天的内容串起来了。你看,四个组件各有专长,但最终都要组合使用。我建议你学完每个组件后,都试着把它们组合成一个小的UI片段。别急着上复杂动画,先把静态界面搭稳了。地基不牢,后面加动画只会越改越乱。