LVGL 是以 obj 为基础衍生出来的一套绘制;每个 obj 都包含了 2 个字段:layout_inv / scr_layout_inv;

typedef struct _lv_obj_t {
......
    uint16_t layout_inv : 1;        // 改 obj 的 layout 是否需要更新
    uint16_t scr_layout_inv : 1;    // screen 的 layout 是否需要更新
......
} lv_obj_t;

可以看到,这里有 2 个字段,接下来我们来看下他们分别代表什么,以及如何使用;

  1. layout_inv lv_obj_mark_layout_as_dirty 的时候标记为 1;
  2. 在 layout_update_core 的时候,判断如果为 0,那么直接返回;
  1. scr_layout_inv lv_obj_mark_layout_as_dirty 的时候标记为 1;
  2. 在 lv_obj_update_layout 的时候判断为 0 的时候,停止更新;

所以,看起来只和几个函数相关:

void lv_obj_mark_layout_as_dirty(lv_obj_t * obj)
{
    obj->layout_inv = 1;

    /*Mark the screen as dirty too to mark that there is something to do on this screen*/
    lv_obj_t * scr = lv_obj_get_screen(obj);
    scr->scr_layout_inv = 1;

    /*Make the display refreshing*/
    lv_disp_t * disp = lv_obj_get_disp(scr);
    if(disp->refr_timer) lv_timer_resume(disp->refr_timer);
}
 

void lv_obj_update_layout(const lv_obj_t * obj)
{
    static bool mutex = false;
    if(mutex) {
        LV_LOG_TRACE("Already running, returning");
        return;
    }
    mutex = true;

    lv_obj_t * scr = lv_obj_get_screen(obj);

    /*Repeat until there where layout invalidations*/
    while(scr->scr_layout_inv) {
        LV_LOG_INFO("Layout update begin");
        scr->scr_layout_inv = 0;
        layout_update_core(scr);
        LV_LOG_TRACE("Layout update end");
    }

    mutex = false;
}

static void layout_update_core(lv_obj_t * obj)
{
    uint32_t i;
    uint32_t child_cnt = lv_obj_get_child_cnt(obj);
    for(i = 0; i < child_cnt; i++) {
        lv_obj_t * child = obj->spec_attr->children[i];
        layout_update_core(child);
    }

    if(obj->layout_inv == 0) return;

    obj->layout_inv = 0;

    lv_obj_refr_size(obj);
    lv_obj_refr_pos(obj);

    if(child_cnt > 0) {
        uint32_t layout_id = lv_obj_get_style_layout(obj, LV_PART_MAIN);
        if(layout_id > 0 && layout_id <= layout_cnt) {
            void  * user_data = LV_GC_ROOT(_lv_layout_list)[layout_id - 1].user_data;
            LV_GC_ROOT(_lv_layout_list)[layout_id - 1].cb(obj, user_data);
        }
    }
}

可以看到:

  1. 通过 lv_obj_mark_layout_as_dirty 来标记当前 obj 为 invalid,即 obj->layout_inv = 1;;
  2. 通过 lv_obj_mark_layout_as_dirty 来获取当前 obj 的 screen (循环获取父对象的方式),并且标记为 invalid,即 scr->scr_layout_inv = 1;;

也就是说,scr_layout_inv 只有 screen 的 obj 才使用,其他的 obj 并没有使用这个结构体中的变量;

在更新 layout 的时候,调用 lv_obj_update_layout:

  1. 首先获取 screen (循环获取父对象的方式),并判断是否 scr->scr_layout_inv 为 invalid;
  2. 如果 screen layout 需要被更新,那么调用 layout_update_core 来对 screen 上的子 obj 循环调用 layout_update_core,此刻需要判断 obj 的 layout_inv;

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐