一、场景引入
在 LVGL 项目开发中,你是否遇到过自定义控件无法复用基础控件的事件回调、修改样式不生效、或者调用通用控件 API 触发异常的问题?这些问题 90% 都是对 LVGL 对象模型和继承机制理解不到位导致的。该考点是 LVGL 二次开发、自定义控件的核心基础,也是面试中区分只会调用 API 和能深度定制 LVGL 开发人员的关键考点。
二、原理解析

LVGL 采用面向对象的设计思想,基于 C 语言实现了单继承的对象模型,核心原理如下:

三、三道递进追问及答案
追问 1:基础追问:lv_btn_t 类型的指针可以直接传给 lv_obj_set_size 函数吗?为什么?
可以。因为 lv_btn_t 的内存布局首地址就是父类 lv_obj_t 的实例结构,所有 LVGL 控件都继承自 lv_obj_t,因此任何控件指针都可以安全强制转为 lv_obj_t * 传入通用 API,LVGL 内部也会做类继承关系校验保证合法性。
追问 2:进阶变形:自定义一个继承自 lv_obj_t 的圆角矩形控件,需要实现哪些关键步骤?
追问 3:实战综合:为什么自定义控件重写了事件回调后,父类的默认绘制行为消失了?怎么解决?
因为 LVGL 的事件处理是链式传递,如果子类回调里直接返回 LV_EVENT_RESULT_OK 而不继续传递事件,父类的事件处理函数就不会被执行。解决方法是子类处理完自身事件后,调用 lv_obj_event_base (class_p->base_class, obj, e) 将事件传递给父类处理,或者只拦截需要重写的事件,其他事件默认传递。
四、最小验证实验
4.1 实验环境
LVGL v8.3.x 仿真环境(PC 端 SDL 仿真、或 ESP32/STM32 LVGL 工程均可,这里采用 PC 端 SDL 仿真环境)
4.2 实验代码
#include "lvgl/lvgl.h"
// 1. 定义自定义圆角矩形类的私有结构
typedef struct {
lv_obj_t base; // 首成员必须是父类结构,实现继承
lv_color_t fill_color; // 自定义属性:填充色
} my_round_rect_t;
// 2. 类事件处理回调
static void my_round_rect_event(const lv_obj_class_t * class_p, lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
my_round_rect_t * obj = (my_round_rect_t *)lv_event_get_current_target(e);
if(code == LV_EVENT_DRAW_MAIN) {
// 子类特有绘制逻辑:输出自定义颜色信息
LV_LOG_USER("Custom rect draw, fill color: 0x%06X", lv_color_to_hex(obj->fill_color));
}
// 调用父类的事件处理,保留基础控件的行为
lv_obj_event_base(class_p->base_class, e->current_target, e);
}
// 3. 类构造函数
static void my_round_rect_constructor(const lv_obj_class_t * class_p, void * obj)
{
LV_UNUSED(class_p);
my_round_rect_t * rect = (my_round_rect_t *)obj;
// 初始化默认属性:圆角半径10,默认填充蓝色
lv_obj_set_style_radius((lv_obj_t *)rect, 10, LV_PART_MAIN);
rect->fill_color = lv_color_hex(0x0088FF);
lv_obj_set_style_bg_color((lv_obj_t *)rect, rect->fill_color, LV_PART_MAIN);
}
// 4. 定义全局类实例,指定继承关系
const lv_obj_class_t my_round_rect_class = {
.base_class = &lv_obj_class, // 父类是lv_obj_t
.instance_size = sizeof(my_round_rect_t), // 实例内存大小
.constructor_cb = my_round_rect_constructor, // 构造函数
.event_cb = my_round_rect_event, // 事件回调
.name = "MyRoundRect", // 类名,调试用
};
// 5. 封装创建API
lv_obj_t * my_round_rect_create(lv_obj_t * parent)
{
return lv_obj_class_create_obj(&my_round_rect_class, parent);
}
// 测试入口
void lv_custom_obj_test(void)
{
// 创建自定义圆角矩形
lv_obj_t * rect = my_round_rect_create(lv_scr_act());
// 调用父类通用API设置尺寸和位置,验证继承有效性
lv_obj_set_size(rect, 200, 100);
lv_obj_center(rect);
// 验证类继承关系
bool is_obj = lv_obj_check_type(rect, &lv_obj_class);
bool is_my_class = lv_obj_check_type(rect, &my_round_rect_class);
LV_LOG_USER("Is base lv_obj_t: %d, Is MyRoundRect: %d", is_obj, is_my_class);
}
4.3 操作步骤
4.4 预期结果




