Edit online

demo

目前支持 demo、meter demo 等 demo

base demo

对 png、jpg 硬件解码,以及 in 的图片使用方式进行演示,UI 界面如下:

../images/base_demo1.png
1. base demo

此 demo 一共有 4 四个页面, 第一个页面为仪表演示、第二个页面为音乐播放演示、第三个页面为菜单演示、 第四个页面为播放器演示。播放器演示页面需要打开 c 中的宏定义 VIDEO_PLAYER

  1. 不同页面通过滑动操作切换,页面滑动使用了控件 tabview
    lv_obj_set_size(main_tabview, 1024, 600);
    lv_obj_set_pos(main_tabview, 0, 0);
    lv_obj_set_style_bg_opa(main_tabview, LV_OPA_0, 0);
    
    lv_obj_t *main_tab0 = lv_tabview_add_tab(main_tabview, "main page 0");
    lv_obj_t *main_tab1 = lv_tabview_add_tab(main_tabview, "main page 1");
    
    lv_obj_set_style_bg_opa(main_tab0, LV_OPA_0, 0);
    lv_obj_set_style_bg_opa(main_tab1, LV_OPA_0, 0);
    lv_obj_set_size(main_tab0, 1024, 600);
    lv_obj_set_size(main_tab1, 1024, 600);
    
    lv_obj_set_pos(main_tab0, 0, 0);
    lv_obj_set_pos(main_tab1, 0, 0);
  2. 背景图片通过 image 控件来创建,是一个名字为 png 的 png 图片,此图片会采用注册的硬件解码器进行解码
    static lv_obj_t *img_bg = NULL;
    img_bg = lv_img_create(lv_scr_act());
    lv_img_set_src(img_bg, LVGL_PATH(global_bg.png));
    lv_obj_set_pos(img_bg, 0, 0);
  3. 菜单图片也通过 image 控件来创建,是 png 图片,此图片也会采用注册的硬件解码器进行解码
    lv_obj_t *sub_image00 = lv_img_create(sub_tab0);
    lv_img_set_src(sub_image00, LVGL_PATH(cook_0.jpg));
    lv_obj_set_pos(sub_image00, 36, 100);
  4. fake image

    fake image 不是一个真实的图片,通过此方式可以方便的对一个矩形区域进行填充:包括 alpha、red、green、blue
    static lv_obj_t *img_bg = NULL;
    FAKE_IMAGE_DECLARE(bg_dark)  // 声明(bg_dark 名字可修改)
    
    /* 最后一个参数为要设置的颜色值:bit31:24 为 alpha */
    FAKE_IMAGE_INIT(bg_dark, 1024, 600, 0, 0x00000000);
    
    lv_img_set_src(img_bg, FAKE_IMAGE_NAME(bg_dark)); // 设置 image 数据源
  5. build-in image 是通过数组变量在程序中表示图像,图片转换成.c 文件的工具参考官网:http://lvgl.io/tools/imageconverter

    uint8_t circle_white_map[] = {
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0xff, 0x7f, 0xff,
            ........................................................};
    
    const lv_img_dsc_t circle_white = {
        .header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
        .header.always_zero = 0,
        .header.reserved = 0,
        .header.w = 20,
        .header.h = 20,
        .data_size = 400 * LV_IMG_PX_SIZE_ALPHA_BYTE,
        .data = circle_white_map,
    };
    
    static lv_obj_t * circle_0 = lv_img_create(img_bg);
    lv_img_set_src(circle_0, &circle_white);
    lv_obj_align(circle_0, LV_ALIGN_BOTTOM_MID, -16, -28);

meter demo

此 demo 演示了硬件旋转,以及仪表盘的设计参考

../images/meter_demo.png
2. meter demo
  1. 其中各种控件的动作通过 timer 来实现,每间隔一定的时间执行相应的 callback
    lv_timer_create(point_callback, 10, 0);
    lv_timer_create(fps_callback, 1000, 0);
    lv_timer_create(speed_callback, 100, 0);
    lv_timer_create(time_callback, 1000 * 60, 0);
  2. 指针和光影通过贴图和硬件任意角度旋转来实现,其中前 74 张指针通过切换 74 张图片来实现, 从第 75 张开始的红色指针,采用硬件任意角度旋转来实现
    static void point_callback(lv_timer_t *tmr)
    {
        char data_str[64];
        (void)tmr;
    
        static bool first = true;
        static int id = 1;
        static int direct = 0;
        static int mode_id = 0;
        static int mode_num = sizeof(rot_mode_list) / sizeof(rot_mode_list[0]);
        static int start_id = 0;
        static int end_id = 0;
    
        if (first) {
            first = false;
            start_id = rot_mode_list[mode_id].start_id;
            end_id = rot_mode_list[mode_id].end_id;
        }
    
        direct = start_id < end_id ? 0: 1;
    
        if (id < 75) {
        lv_img_set_src(img_circle, LVGL_PATH(bg/small_blue.png));
        lv_obj_clear_flag(img_circle, LV_OBJ_FLAG_HIDDEN);
        } else {
        lv_obj_add_flag(img_circle, LV_OBJ_FLAG_HIDDEN);
        }
    
        if (id < 75) {
            sprintf(data_str, "%spoint/point_%05d.png", LVGL_DIR, id);
            lv_img_set_src(img_point, data_str);
            lv_img_set_angle(img_point, 0);
    
        } else {
            // id to angle
            float rot_angle = ((float)(id - 75) * 2 * 10) * 0.84;
            sprintf(data_str, "%spoint/point_%05d.png", LVGL_DIR, 75);
            lv_img_set_src(img_point, data_str);
            lv_img_set_pivot(img_point, 210, 210);
            lv_img_set_angle(img_point, (int16_t)rot_angle);
        }
    
        if (direct == 0) {
            id++;
        } else {
            id--;
        }
    
        if ((!direct && (id > end_id) ) ||
            (direct && (id < end_id))) {
            id = end_id;
            mode_id++;
            mode_id %= mode_num;
            start_id = rot_mode_list[mode_id].start_id;
            end_id = rot_mode_list[mode_id].end_id;
        }
    
        return;
    }
  3. UI 怎么设计更高效?

    针对本 demo 场景给出两种流程:
    • UI 设计方案 1
      ../images/meter_draw_1.png
      3. UI 设计方案 1
      • 需要光条、指针、光圈、底图四张

      • 首先光圈和背景进行 blending,然后光条和背景进行 blending,最后指针和背景进行 alpha blending

      • 每一个角度的旋转都需要进行 3 次 alpha blending

    • UI 设计方案 2
      ../images/meter_draw_2.png
      4. UI 设计方案 2
      • 光条和指针合并为一张图

      • 光圈合并到背景图中

      • 需要光条和指针图片和底图 2 张图片

      • 每一个角度的旋转都只需要光条和指针图片与背景图进行一次 alpha blending

      显然 UI 设计方案 2 更高效,实现同样的界面效果,简化流程速度可以提升一倍以上