4、UI组件基础:按钮(Button)、文本框(TextArea)、图像(Image)的使用与属性配置
好,咱们今天聊聊TouchGFX里最常用的三个基础组件——按钮、文本框和图像。别看它们基础,我做了这么多项目,发现很多界面问题其实都出在对这三个组件的理解不够深上。你想想看,一个交互界面,用户能点的是按钮,能看到的是图像,能读的是文字。这三个东西用好了,界面就成功了一大半。
4.1 按钮(Button):不只是“点一下”那么简单
按钮是用户和系统交互最直接的入口。在TouchGFX里,按钮本质上是一个可以响应点击事件的图像容器。嗯,这里要注意,它和我们平时理解的“按钮”不太一样——它本身没有固定的形状,全靠你给它贴的图片来定义外观。
4.1.1 按钮的三种状态
一个标准的按钮,至少需要准备两张图片:
- Released(释放态):按钮没被按下时的样子
- Pressed(按下态):用户手指或鼠标按下时的样子
我个人习惯再加一张Disabled(禁用态)的图片,虽然它不是必须的。为什么?因为我在项目中遇到过用户快速连点导致界面卡死的情况,后来发现是按钮在禁用状态下没有视觉反馈,用户以为没点到,就一直点。加上禁用态的图片后,问题就解决了。
关键属性配置:
Bitmaps(位图):分别指定Released和Pressed状态的图片Alpha(透明度):0-255,255为完全不透明。我一般禁用态设成128Touchable(可触摸):是否响应点击事件。调试时我经常关掉这个
4.1.2 按钮的交互逻辑
按钮的点击事件在TouchGFX里是通过回调函数实现的。说白了,就是你在代码里告诉系统:“当这个按钮被按下时,去执行某某函数”。
// 在视图头文件中声明回调
#include <touchgfx/widgets/Button.hpp>
class MainView : public MainViewBase {
public:
MainView();
virtual ~MainView() {}
virtual void setupScreen();
virtual void tearDownScreen();
// 按钮点击回调
void buttonClickedHandler(const AbstractButton& button);
protected:
Button myButton;
};
// 在源文件中实现
void MainView::setupScreen() {
// 配置按钮位置和大小
myButton.setXY(100, 200);
myButton.setBitmaps(
Bitmap(BITMAP_BUTTON_RELEASED_ID), // 释放态图片
Bitmap(BITMAP_BUTTON_PRESSED_ID) // 按下态图片
);
// 绑定回调
myButton.setAction(buttonClickedHandler);
add(myButton); // 别忘了添加到视图
}
void MainView::buttonClickedHandler(const AbstractButton& button) {
if (&button == &myButton) {
// 执行你的逻辑
// 比如切换页面、发送数据等
}
}
我的小技巧:按钮图片的尺寸最好做成2的倍数,比如80x40、120x60。TouchGFX底层对2的倍数尺寸有优化,渲染性能会好一些。另外,Released和Pressed两张图片的尺寸必须一致,否则切换时界面会跳一下。
4.2 文本框(TextArea):让界面“说话”
文本框是显示文字的基础组件。在TouchGFX里,TextArea和TextAreaWithOneWildcard是两个最常用的。前者显示固定文本,后者可以显示动态内容——比如温度值、设备状态等。
4.2.1 文本的显示机制
TouchGFX的文本渲染和PC上不太一样。它用的是字模(Glyph)方式——每个字符都预先渲染成位图,显示时直接贴图。这样做的好处是速度快,坏处是字体文件会比较大。
| 属性 | 说明 | 我的建议 |
|---|---|---|
TypedText |
指定使用的文字样式(字体、大小、颜色) | 在Texts文件夹里统一管理,别在代码里硬编码 |
Wildcard |
动态内容的占位符,比如显示“温度:%d°C” | 用TextAreaWithOneWildcard,别自己拼字符串 |
Alignment |
左对齐、居中、右对齐 | 中文建议左对齐,英文可以居中 |
Linespace |
行间距,单位像素 | 默认0,中文建议设2-4,否则字会挤在一起 |
4.2.2 动态文本的更新
我曾经做过一个温控器项目,需要实时显示温度。一开始我用的是TextArea,每次更新都重新创建字符串,结果内存泄漏了。后来改用TextAreaWithOneWildcard,问题迎刃而解。
// 使用TextAreaWithOneWildcard显示动态数据
class TemperatureView : public TemperatureViewBase {
public:
void updateTemperature(int temp) {
// 将整数转换为字符串
Unicode::snprintf(textBuffer, TEXTBUFFER_SIZE, "%d", temp);
// 刷新显示
temperatureText.setWildcard(textBuffer);
temperatureText.invalidate();
}
protected:
static const uint16_t TEXTBUFFER_SIZE = 10;
Unicode::UnicodeChar textBuffer[TEXTBUFFER_SIZE];
TextAreaWithOneWildcard temperatureText;
};
注意:TextArea的缓冲区大小一定要留够。我见过有人设了5个字符的缓冲区,结果显示“温度:25.5°C”时直接溢出崩溃。建议缓冲区大小至少是实际内容的2倍。
4.3 图像(Image):界面的“颜值担当”
图像组件在TouchGFX里是最灵活的。它不仅可以显示静态图片,还能做缩放、旋转、透明度变化等效果。但要注意,图像组件的性能开销比按钮和文本框大得多。
4.3.1 图像的加载与显示
TouchGFX支持PNG、JPG、BMP等常见格式,但最终都会转换成内部位图格式。我建议所有图片都用PNG,因为它支持透明通道,而且压缩率不错。
// 图像组件的典型用法
Image logoImage;
// 设置位置和大小
logoImage.setXY(50, 50);
logoImage.setBitmap(Bitmap(BITMAP_LOGO_ID));
// 缩放显示(保持宽高比)
logoImage.setScalingMode(Image::SCALE_MODE_KEEP_ASPECT_RATIO);
logoImage.setWidth(200);
logoImage.setHeight(100);
// 设置透明度(实现淡入淡出效果)
logoImage.setAlpha(128); // 半透明
add(logoImage);
4.3.2 图像的性能优化
图像是界面卡顿的“头号元凶”。我在一个项目里用了10张1920x1080的全屏图片做轮播,结果帧率直接掉到15fps。后来做了三件事才解决:
- 控制图片尺寸:不要用比显示区域大的图片。比如显示区域是200x100,图片就做成200x100,别用400x200的再缩小
- 使用压缩格式:TouchGFX支持L8和RGB565格式。L8是256色,适合图标;RGB565是16位色,适合照片
- 减少Alpha混合:每层透明度叠加都会增加渲染开销。能不用透明就不用
图像格式选择指南:
| 场景 | 推荐格式 | 原因 |
|---|---|---|
| 图标、按钮 | L8(256色) | 体积小,渲染快,支持透明 |
| 照片、背景 | RGB565 | 色彩丰富,16位色够用 |
| 需要Alpha渐变 | ARGB8888 | 8位Alpha通道,效果最好但最慢 |
4.4 三个组件的协同工作
在实际项目中,按钮、文本框和图像很少单独使用。它们通常会组合成一个完整的交互单元。比如一个设置界面:
- 背景用图像组件显示
- 标题用文本框显示
- 操作按钮用按钮组件实现
我习惯在TouchGFX Designer里先把布局搭好,然后再到代码里添加交互逻辑。这样效率最高,而且不容易出错。
布局小技巧:在Designer里,选中多个组件后可以用“Align”工具快速对齐。我经常用“Distribute horizontally”让按钮均匀分布,比手动调坐标快多了。
好了,这三个组件是TouchGFX界面开发的基石。你先把它们练熟,后面讲容器、列表、滑动页面时,你会发现很多高级组件其实就是这些基础组件的组合和封装。嗯,今天就到这里,动手试试吧。