txtlite控件¶
1. 使用场景¶
txtlite 是基于 LVGL + VGLite 硬件加速实现的高性能文本/图形渲染控件,核心面向嵌入式UI场景,尤其适用于以下需求:
需要3D变换效果(如旋转、缩放、位移)的文本展示场景;
需实现丰富动画效果(飞入、跳跃、环形运动、缩放等)的UI交互场景;
2. 接口介绍¶
接口函数 |
功能说明 |
参数说明 |
|---|---|---|
lv_obj_t *lv_txtlite_create(lv_obj_t *parent) |
创建txtlite自定义控件实例,基于LVGL图像对象扩展,是使用控件的基础入口 |
parent:父LVGL对象指针(如屏幕、容器) |
void lv_txtlite_init(lv_obj_t *txtlite, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf, uint32_t flag) |
初始化控件核心渲染参数,创建控件后必须立即调用 |
txtlite:已创建的控件实例指针;w:控件宽度(LVGL坐标单位);h:控件高度(LVGL坐标单位);cf:帧缓冲颜色格式(需匹配VGLite硬件支持格式);flag:初始化标志位(BIT0:异步渲染;BIT1:硬件加速;BIT2:双缓冲;BIT3:抗锯齿) |
void lv_txtlite_refr(lv_obj_t *txtlite) |
强制刷新控件渲染内容,手动触发全量重绘(文本、多边形、动画) |
txtlite:已初始化的控件实例指针 |
void lv_txtlite_set_bg_color(lv_obj_t *txtlite, vg_lite_color_t color) |
设置控件渲染区域的纯色背景色 |
txtlite:已初始化的控件实例指针;color:VGLite格式背景色(包含r/g/b/a分量) |
lv_txtlite_item_t *lv_txtlite_add_face_polygon(lv_obj_t *txtlite, const vg_lite_vertex_t *point, uint16_t cnt, uint32_t color, void *uset_data) |
添加多边形面到控件,基于VGLite硬件加速渲染填充多边形 |
txtlite:已初始化的控件实例指针;point:多边形顶点数组(x/y/z坐标);cnt:顶点数量(≥3且≤CUBE_POINT_MAX);color:32位RGBA填充色;uset_data:用户自定义数据指针 |
void lv_txtlite_add_txt(lv_obj_t *txtlite, const char *txt, lv_align_t align, lv_coord_t ofs_x, lv_coord_t ofs_y) |
添加文本项到控件,结合LVGL文本渲染和VGLite加速 |
txtlite:已初始化的控件实例指针;txt:待显示的以’\0’结尾的文本串(支持ASCII/UTF-8);align:文本相对控件的对齐方式;ofs_x:水平偏移量;ofs_y:垂直偏移量 |
void lv_txtlite_set_rot(lv_obj_t *txtlite, vg_lite_matrix_4x4_t *rot) |
设置控件整体3D旋转矩阵,实现3D旋转和透视效果 |
txtlite:已初始化的控件实例指针;rot:4x4旋转/变换矩阵指针 |
void lv_txtlite_get_rot(lv_obj_t *txtlite, vg_lite_matrix_4x4_t *rot) |
获取控件当前3D旋转矩阵,读取旋转状态 |
txtlite:已初始化的控件实例指针;rot:存储矩阵的输出指针(需预分配) |
void lv_txtlite_set_zoom(lv_obj_t *txtlite, float scale) |
设置控件整体缩放因子,覆盖现有缩放动画(直至重启动画) |
txtlite:已初始化的控件实例指针;scale:缩放因子(≥0.1,1.0为原始尺寸,负数忽略) |
float lv_txtlite_get_zoom(lv_obj_t *txtlite) |
获取控件当前缩放因子(含静态设置/动画动态值) |
txtlite:已初始化的控件实例指针 |
void lv_txtlite_reset_pos(lv_obj_t *txtlite, uint32_t flag) |
重置控件位置/变换状态到默认值 |
txtlite:已初始化的控件实例指针;flag:重置标志位(BIT0:位置;BIT1:旋转矩阵;BIT2:缩放;BIT3:全部) |
void lv_txtlite_save_pos(lv_obj_t *txtlite, uint32_t flag) |
保存控件当前位置/变换状态到内部缓冲区 |
txtlite:已初始化的控件实例指针;flag:保存标志位(BIT0:位置;BIT1:旋转矩阵;BIT2:缩放;BIT3:全部) |
lv_txtlite_fly_in_para_t *lv_txtlite_add_fly_in_anim(lv_obj_t *txtlite, uint32_t start_time, uint32_t dur_time, uint32_t flag) |
添加飞入动画,控件从起始位置飞至当前位置 |
txtlite:已初始化的控件实例指针;start_time:动画启动延迟(ms);dur_time:动画时长(ms,≥10);flag:动画标志位(轴/循环/缓动等) |
lv_txtlite_move_para_t *lv_txtlite_add_move_anim(lv_obj_t *txtlite, uint32_t start_time, uint32_t dur_time, uint32_t flag) |
添加线性移动动画,控件匀速从当前位置移至目标位置 |
txtlite:已初始化的控件实例指针;start_time:动画启动延迟(ms);dur_time:动画时长(ms,≥10);flag:动画标志位(轴/循环/乒乓模式等) |
lv_txtlite_jump_para_t *lv_txtlite_add_jump_anim(lv_obj_t *txtlite, uint32_t start_time, uint32_t dur_time, uint32_t flag) |
添加跳跃动画,控件沿抛物线轨迹弹跳 |
txtlite:已初始化的控件实例指针;start_time:动画启动延迟(ms);dur_time:动画时长(ms,≥50);flag:动画标志位(2D/3D/循环/重力模拟等) |
lv_txtlite_zoom_para_t *lv_txtlite_add_zoom_anim(lv_obj_t *txtlite, uint32_t start_time, uint32_t dur_time, uint32_t flag) |
添加缩放动画,控件从当前尺寸缩放到目标尺寸 |
txtlite:已初始化的控件实例指针;start_time:动画启动延迟(ms);dur_time:动画时长(ms,≥10);flag:动画标志位(均匀/非均匀缩放/循环/缓动等) |
lv_txtlite_ring_para_t *lv_txtlite_add_ring_anim(lv_obj_t *txtlite, uint32_t start_time, uint32_t dur_time, uint32_t flag) |
添加环形动画,为控件添加环形运动效果 |
txtlite:已初始化的控件实例指针;start_time:动画启动延迟(ms);dur_time:动画时长(ms);flag:动画控制标志位 |
void lv_txtlite_start_anim(lv_obj_t *txtlite) |
启动所有已添加的动画,按添加顺序执行 |
txtlite:已初始化的控件实例指针 |
void lv_txtlite_clear_all_anim(lv_obj_t *txtlite) |
停止并清除所有动画,保留控件当前状态 |
txtlite:已初始化的控件实例指针 |
3. 使用案例¶
3.1 环形转动歌词动效¶
#define VG_TXTLITE_MOVE LV_SCENE_STYLE_CUSTOMER
#define VG_TXTLITE_RING (LV_SCENE_STYLE_CUSTOMER + 1)
void txtlite_add_lyric(lv_obj_t *txtlite, const char *str)
{
if (!str || !str[0]) return;
int32_t child_cnt = lv_obj_get_child_cnt(txtlite);
while (child_cnt > 1)
{
lv_obj_t *child = lv_obj_get_child(txtlite, 0);
lv_obj_del(child);
child_cnt--;
}
float target_z = -5 * LV_HOR_RES_MAX / LV_VER_RES_MAX;
float target_x = target_z * 1.5f;
for (uint32_t i = 0; i < child_cnt; i++)
{
lv_obj_t *child = lv_obj_get_child(txtlite, i);
lv_txtlite_clear_all_anim(child);
if (VG_TXTLITE_MOVE == music_get_nvm()->lyric_style)
lv_txtlite_reset_pos(child, 0x2);
vg_lite_matrix_4x4_t rot;
lv_txtlite_get_rot(child, &rot);
float z = target_z * (child_cnt - i) - rot.m[2][3];
float x = target_x * (child_cnt - i) - rot.m[0][3];
lv_txtlite_move_para_t *p_para = NULL;
p_para = lv_txtlite_add_move_anim(child, 0, 1000, 0);
p_para->offset.x = x;
p_para->offset.y = 1;
p_para->offset.z = z;
p_para->x_deg = 0;
p_para->y_deg = 0;
p_para->z_deg = 0;
lv_txtlite_start_anim(child);
}
lv_obj_t *sub = lv_txtlite_create(txtlite);
const lv_font_t *font = lv_obj_get_style_text_font(sub, 0);
if (music_lyric->font_cnt)
{
char *font_name = (char *)music_lyric->font_names[0];
#if LV_HOR_RES_MAX < 600
uint16_t font_size = music_lyric->font_size_arr[LV_SCENE_FONT_BIG];
#else
uint16_t font_size = music_lyric->font_size_arr[LV_SCENE_FONT_HUG];
#endif
font = lvsf_get_font_by_name(font_name, font_size);
lv_obj_set_style_text_font(sub, font, 0);
}
if (VG_TXTLITE_MOVE == music_get_nvm()->lyric_style)
{
uint32_t str_len = strlen(str);
char *str_buf = app_calloc(1, str_len + 16);
RT_ASSERT(str_buf);
uint32_t src_offset = 0;
uint32_t dst_offset = 0;
uint32_t line_cnt = 0;
for (uint32_t i = 0; i < 15 && str[src_offset]; i++)
{
uint32_t len = _lv_txt_get_next_line(&str[src_offset], font, 0, LV_HOR_RES_MAX * 3 / 4, NULL, 0);
rt_memcpy(str_buf + dst_offset, &str[src_offset], len);
dst_offset += len;
str_buf[dst_offset] = 0;
dst_offset++;
src_offset += len;
line_cnt++;
}
lv_coord_t pos_y = ((line_cnt - 1) * font->line_height) >> 1;
dst_offset = 0;
for (uint32_t i = 0; i < line_cnt; i++)
{
lv_txtlite_add_txt(sub, &str_buf[dst_offset], LV_ALIGN_CENTER, 0, pos_y);
dst_offset += strlen(&str_buf[dst_offset]) + 1;
pos_y -= font->line_height;
}
app_free(str_buf);
vg_lite_matrix_4x4_t rot;
vg_lite_identity_4x4(&rot);
lv_coord_t angle_z = rand() % 30 - 15;
angle_z = angle_z > 0 ? (angle_z + 15) : (angle_z - 15);
vg_lite_rotate_z(angle_z, &rot);
lv_coord_t angle_x = rand() % 60 - 30;
angle_x = angle_x > 0 ? (angle_x + 20) : (angle_x - 20);
vg_lite_rotate_x(angle_x, &rot);
vg_lite_rotate_y(rand() % 20 - 10, &rot);
lv_txtlite_set_rot(sub, &rot);
lv_txtlite_fly_in_para_t *p_para = NULL;
p_para = lv_txtlite_add_fly_in_anim(sub, 0, 1000, 0);
p_para->offset.x = 2.f;
p_para->offset.y = rand() % 300 / 100 - 1.5f;
p_para->offset.z = 0;
lv_txtlite_add_zoom_anim(sub, 1000, 3000, LV_TXTLITE_ANIM_LOOP);
lv_txtlite_start_anim(sub);
}
else if (VG_TXTLITE_RING == music_get_nvm()->lyric_style)
{
lv_txtlite_add_txt(sub, str, LV_ALIGN_CENTER, 0, FONT_NORMAL);
lv_txtlite_ring_para_t *p_para = NULL;
p_para = lv_txtlite_add_ring_anim(sub, 0, 1000, LV_TXTLITE_ANIM_LOOP);
p_para->angle_v = 1.f;
p_para->norm.x = 0.1f + rand() % 90 / (float)100;
p_para->norm.y = rand() % 100 / (float)100;
p_para->norm.z = rand() % 100 / (float)100;
lv_txtlite_start_anim(sub);
}
lv_txtlite_start_anim(txtlite);
}
lv_obj_t *music_create_txtlite(lv_obj_t *parent)
{
//同步刷新
lv_obj_set_render_async(lv_scr_act(), 0);
lv_obj_t *img_bg = lv_img_create(parent);
lv_img_set_src(img_bg, APP_GET_IMG(img_txt_bg));
lv_coord_t w = lv_obj_get_self_width(img_bg);
if (w && w != LV_HOR_RES_MAX)
lv_img_set_zoom(img_bg, LV_HOR_RES_MAX * LV_IMG_ZOOM_NONE / w);
lv_obj_center(img_bg);
lv_obj_t *txtlite = lv_txtlite_create(parent);
lv_txtlite_init(txtlite, LV_HOR_RES_MAX, LV_VER_RES_MAX, LV_IMG_CF_ALPHA_8BIT, 0);
lv_obj_update_layout(txtlite);
lv_obj_center(txtlite);
lv_ext_set_local_font(txtlite, FONT_HUGE, LV_COLOR_RED);
lv_obj_set_style_img_recolor_opa(txtlite, LV_OPA_100, 0);
lv_obj_set_style_img_recolor(txtlite, LV_COLOR_RED, 0);
music_lyric->txtlite = txtlite;
//、、、、
}
3.2 案例效果展示¶
4. 注意事项¶
4.1 初始化相关¶
必须在
lv_txtlite_create后立即调用lv_txtlite_init,否则控件无法正常渲染;多次调用
lv_txtlite_init会覆盖原有参数并重置控件状态,需避免重复调用。文本渲染默认使用LVGL默认字体,可通过LVGL字体接口(
lv_font_set_default)修改;旋转矩阵需符合VGLite右手坐标系规范(默认Y轴向下),非法矩阵(如奇异矩阵)会导致渲染异常;
清空动画(
lv_txtlite_clear_all_anim)仅停止动画,不会重置控件位置/缩放状态。