嵌入式UI框架 LVGL 学习笔记 01 基础概念

基础组件研究

Code地址:https://github.com/lvgl

中文参考文档(可能部分内容不匹配,仅参考):http://lvgl.100ask.net/8.2/index.html
官方API参考文档地址:https://docs.lvgl.io/master/intro/index.html
注意:LVGL 7.x版本与8.x版本差别很大,建议使用8.x版本

Windows 模拟器

  • Clone https://github.com/lvgl/lv_sim_visual_studio.git
  • 查看依赖的lv_drivers和lvgl是否下载,地址https://github.com/lvgl/lvgl https://github.com/lvgl/lv_drivers
  • VS2019 打开 LVGL.Simulator.sln
  • Rebuild & Run

入口程序 LVGL.Simulator.cpp, 需要按照自己的需求,释放对应的example code. UI大小默认800*480

/*
 * PROJECT:   LVGL PC Simulator using Visual Studio
 * FILE:      LVGL.Simulator.cpp
 * PURPOSE:   Implementation for LVGL ported to Windows Desktop
 *
 * LICENSE:   The MIT License
 *
 * DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com)
 */

#include <Windows.h>

#include "resource.h"

#if _MSC_VER >= 1200
 // Disable compilation warnings.
#pragma warning(push)
// nonstandard extension used : bit field types other than int
#pragma warning(disable:4214)
// 'conversion' conversion from 'type1' to 'type2', possible loss of data
#pragma warning(disable:4244)
#endif

#include "lvgl/lvgl.h"
#include "lvgl/examples/lv_examples.h"
#include "lvgl/demos/lv_demos.h"
#include "lv_drivers/win32drv/win32drv.h"

#if _MSC_VER >= 1200
// Restore compilation warnings.
#pragma warning(pop)
#endif

#include <stdio.h>

int main()
{
    
    
    lv_init();

    if (!lv_win32_init(
        GetModuleHandleW(NULL),
        SW_SHOW,
        800,
        480,
        LoadIconW(GetModuleHandleW(NULL), MAKEINTRESOURCE(IDI_LVGL))))
    {
    
    
        return -1;
    }

    lv_win32_add_all_input_devices_to_group(NULL);

    /*
     * Demos, benchmarks, and tests.
     *
     * Uncomment any one (and only one) of the functions below to run that
     * item.
     */

    // ----------------------------------
    // my freetype application
    // ----------------------------------

    ///*Init freetype library
    // *Cache max 64 faces and 1 size*/
    //lv_freetype_init(64, 1, 0);

    ///*Create a font*/
    //static lv_ft_info_t info;
    //info.name = "./lvgl/src/extra/libs/freetype/arial.ttf";
    //info.weight = 36;
    //info.style = FT_FONT_STYLE_NORMAL;
    //lv_ft_font_init(&info);

    ///*Create style with the new font*/
    //static lv_style_t style;
    //lv_style_init(&style);
    //lv_style_set_text_font(&style, info.font);

    ///*Create a label with the new style*/
    //lv_obj_t* label = lv_label_create(lv_scr_act());
    //lv_obj_add_style(label, &style, 0);
    //lv_label_set_text(label, "FreeType Arial Test");

    // ----------------------------------
    // my Win32 filesystem driver application
    // ----------------------------------

    /*::lv_fs_win32_init();

    lv_fs_dir_t d;
    if (lv_fs_dir_open(&d, "/") == LV_FS_RES_OK)
    {
        char b[MAX_PATH];
        memset(b, 0, MAX_PATH);
        while (lv_fs_dir_read(&d, b) == LV_FS_RES_OK)
        {
            printf("%s\n", b);
        }

        lv_fs_dir_close(&d);
    }*/

    // ----------------------------------
    // Demos from lv_examples
    // ----------------------------------

    // lv_demo_widgets();           // ok
    // lv_demo_benchmark();
    // lv_demo_keypad_encoder();    // ok
    // lv_demo_music();             // removed from repository
    // lv_demo_printer();           // removed from repository
    // lv_demo_stress();            // ok

    // ----------------------------------
    // LVGL examples
    // ----------------------------------

    /*
     * There are many examples of individual widgets found under the
     * lvgl\exampless directory.  Here are a few sample test functions.
     * Look in that directory to find all the rest.
     */

    // lv_ex_get_started_1();
    // lv_ex_get_started_2();
    // lv_ex_get_started_3();

    // lv_example_flex_1();
    // lv_example_flex_2();
    // lv_example_flex_3();
    // lv_example_flex_4();
    // lv_example_flex_5();
    // lv_example_flex_6();        // ok

    // lv_example_grid_1();
    // lv_example_grid_2();
    // lv_example_grid_3();
    // lv_example_grid_4();
    // lv_example_grid_5();
    // lv_example_grid_6();

    lv_port_disp_template();
    // lv_port_fs_template();
    // lv_port_indev_template();

    // lv_example_scroll_1();
    // lv_example_scroll_2();
    // lv_example_scroll_3();

    // lv_example_style_1();
    // lv_example_style_2();
    // lv_example_style_3();
    // lv_example_style_4();        // ok
    // lv_example_style_6();        // file has no source code
    // lv_example_style_7();
    // lv_example_style_8();
    // lv_example_style_9();
    // lv_example_style_10();
    // lv_example_style_11();       // ok

    // ----------------------------------
    // LVGL widgets examples
    // ----------------------------------

    // lv_example_arc_1();
    // lv_example_arc_2();

    // lv_example_bar_1();          // ok
    // lv_example_bar_2();
    // lv_example_bar_3();
    // lv_example_bar_4();
    // lv_example_bar_5();
    // lv_example_bar_6();          // issues

    // lv_example_btn_1();
    // lv_example_btn_2();
    // lv_example_btn_3();

    // lv_example_btnmatrix_1();
    // lv_example_btnmatrix_2();
    // lv_example_btnmatrix_3();

    // lv_example_calendar_1();

    // lv_example_canvas_1();
    // lv_example_canvas_2();

    // lv_example_chart_1();        // ok
    // lv_example_chart_2();        // ok
    // lv_example_chart_3();        // ok
    // lv_example_chart_4();        // ok
    // lv_example_chart_5();        // ok
    // lv_example_chart_6();        // ok

    // lv_example_checkbox_1();

    // lv_example_colorwheel_1();   // ok

    // lv_example_dropdown_1();
    // lv_example_dropdown_2();
    // lv_example_dropdown_3();

    // lv_example_img_1();
    // lv_example_img_2();
    // lv_example_img_3();
    // lv_example_img_4();         // ok

    //lv_example_imgbtn_1();

    // lv_example_keyboard_1();    // ok

    // lv_example_label_1();
    // lv_example_label_2();       // ok

    // lv_example_led_1();

    // lv_example_line_1();

    // lv_example_list_1();

    // lv_example_meter_1();
    // lv_example_meter_2();
    // lv_example_meter_3();
    // lv_example_meter_4();       // ok

    // lv_example_msgbox_1();

    // lv_example_obj_1();         // ok

    // lv_example_roller_1();
    // lv_example_roller_2();      // ok

    // lv_example_slider_1();      // ok
    // lv_example_slider_2();      // issues
    // lv_example_slider_3();      // issues

    // lv_example_spinbox_1();

    // lv_example_spinner_1();     // ok

    // lv_example_switch_1();      // ok

    // lv_example_table_1();
    // lv_example_table_2();       // ok

    // lv_example_tabview_1();

    // lv_example_textarea_1();    // ok
    // lv_example_textarea_2();
    // lv_example_textarea_3();    // ok, but not all button have functions

    // lv_example_tileview_1();    // ok

    // lv_example_win_1();         // ok
    // ----------------------------------
    // Task handler loop
    // ----------------------------------

    while (!lv_win32_quit_signal)
    {
    
    
        lv_task_handler();
        Sleep(1);
    }

    return 0;
}

单片机如何集成

  • 使用git命令 git clone https://github.com/lvgl/lvgl.git 从 GitHub 下载或克隆库。
  • lvgl 文件夹复制到您的项目中。
  • lvgl/lv_conf_template.h 作为 lv_conf.h 复制到 lvgl 文件夹旁边,将其第一个的 #if 0 更改为 1 以使能文件的内容并修改设置 LV_COLOR_DEPTH 宏。
  • 在需要使用 LVGL 相关函数的文件中包含 lvgl/lvgl.h
  • 在计时器或任务中每 x 毫秒调用一次 lv_tick_inc(x)x 应该在 1 到 10 之间)。 LVGL 的内部时序需要它。或者,配置 LV_TICK_CUSTOM(参见 lv_conf.h ),以便 LVGL 可以直接检索当前时间。
  • 调用 lv_init() (初始化lvgl库)
  • 创建一个绘制缓冲区:LVGL 将首先在此处渲染图形,并将渲染的图像发送到显示器。 缓冲区大小可以自由设置,但 1/10 屏幕大小是一个很好的起点。
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES / 10];                        /*Declare a buffer for 1/10 screen size*/
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, MY_DISP_HOR_RES * MY_DISP_VER_RES / 10);  /*Initialize the display buffer.*/
  • 实现并注册一个函数,该函数可以将渲染图像复制到显示区域:
lv_disp_drv_t disp_drv;               /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv);          /*Basic initialization*/
disp_drv.flush_cb = my_disp_flush;    /*Set your driver function*/
disp_drv.buffer = &draw_buf;          /*Assign the buffer to the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;   /*Set the horizontal resolution of the display*/
disp_drv.hor_res = MY_DISP_VER_RES;   /*Set the verizontal resolution of the display*/
lv_disp_drv_register(&disp_drv);      /*Finally register the driver*/

void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
    
    
    int32_t x, y;
    /*It's a very slow but simple implementation.
     *`set_pixel` needs to be written by you to a set pixel on the screen*/
    for(y = area->y1; y <= area->y2; y++) {
    
    
        for(x = area->x1; x <= area->x2; x++) {
    
    
            set_pixel(x, y, *color_p);
            color_p++;
        }
    }

    lv_disp_flush_ready(disp);         /* Indicate you are ready with the flushing*/
}
  • 实现并注册一个可以读取输入设备的函数。例如。对于触摸板:
lv_indev_drv_t indev_drv;                  /*Descriptor of a input device driver*/
lv_indev_drv_init(&indev_drv);             /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER;    /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_touchpad_read;      /*Set your driver function*/
lv_indev_drv_register(&indev_drv);         /*Finally register the driver*/

bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
{
    
    
    /*`touchpad_is_pressed` and `touchpad_get_xy` needs to be implemented by you*/
    if(touchpad_is_pressed()) {
    
    
      data->state = LV_INDEV_STATE_PRESSED;
      touchpad_get_xy(&data->point.x, &data->point.y);
    } else {
    
    
      data->state = LV_INDEV_STATE_RELEASED;
    }
 
}
  • 在主while(1) 循环或操作系统任务中每隔几毫秒定期调用lv_timer_handler()。 如果需要,它将重绘屏幕,处理输入设备,动画等。

基础概念

  • 组织关系
    LVGL从屏幕对象开始,一层层的父子关系传递下去,组成了组件树。
    子项只有在父项上时可见,父项销毁,子项也会被删除掉。
    如果父节点的位置发生变化,子节点将与父节点一起移动。 因此,所有位置都相对于父级。
  • 屏幕
    屏幕是没有父对象的特殊对象。所以它们可以像这样创建:lv_obj_t * scr1 = lv_obj_create(NULL);
    屏幕是在当前选择的_默认显示_上创建的。 default display 是最后一个用lv_disp_drv_register 注册的显示,或者你可以使用lv_disp_set_default(disp) 明确地选择一个新的默认显示。
    LVGL支持多个屏幕,所以支持多个根对象。lv_scr_act()获取当前屏幕,lv_src_load(src1)加载一个屏幕。lv_scr_load_anim设置屏幕切换动画。
  • Layers(层)
    Screen有两个自动生成的层:顶层, 系统层 它们独立于屏幕,将显示在每个屏幕上。
    顶层位于屏幕上的每个对象之上,系统层也位于顶层之上。 您可以自由地将任何弹出窗口添加到顶层。但是,系统层仅限于系统级事物(如:鼠标).
    lv_layer_top()lv_layer_sys() 函数分别返回指向顶层和系统层的指针。
  • 常用函数
    lv_obj_t* p = lv_<type>_create(parent);创建一个UI对象。
    lv_obj_set_<parameter_name>(obj, <value>); 通用的设置对象属性方法。包含x,y,pos,width,height,size,....
    lv_<widget_type>_set_<parameter_name>(obj, <value>); 针对个别UI有自己的特殊参数设定
  • 事件 Event
    LVGL中UI对象发生了变化,会触发一个event, 它包含点击、拖动、删除等。
    一般通过lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED/LV_EVENT_ALL, NULL);来设定。
    在回调函数中,通过lv_event_code_t code = lv_event_get_code(e); 可以得到事件代码,通过lv_obj_t * obj = lv_event_get_target(e);得到出发事件的对象。
  • 部件 Parts
    一个UI对象可能由一个或多个部分构建,成为部件。不同UI对象的部件数量是不同的。
    如:按钮只有LV_PART_MAIN, 滑块就有LV_PART_MAIN, LV_PART_INDICATOR, LV_PART_KNOB 三部分组成。
    • LV_PART_MAIN 类似矩形的背景
    • LV_PART_SCROLLBAR 滚动条
    • LV_PART_INDICATOR 指标,例如用于滑块、条、开关或复选框的勾选框
    • LV_PART_KNOB 像手柄一样可以抓取调整值
    • LV_PART_SELECTED 表示当前选择的选项或部分
    • LV_PART_ITEMS 如果小部件有多个相似的元素(例如表格单元格)
    • LV_PART_TICKS 刻度上的刻度,例如对于图表或仪表
    • LV_PART_CURSOR 标记一个特定的地方,例如文本区域或图表的光标
    • LV_PART_CUSTOM_FIRST 可以从这里添加自定义部件。
  • 状态 Status
    每个UI部件都是很多状态的组合体,一般有如下状态:
    • LV_STATE_DEFAULT 正常,释放状态
    • LV_STATE_CHECKED 切换或选中状态
    • LV_STATE_FOCUSED 通过键盘或编码器聚焦或通过触摸板/鼠标点击
    • LV_STATE_FOCUS_KEY 通过键盘或编码器聚焦,但不通过触摸板/鼠标聚焦
    • LV_STATE_EDITED 由编码器编辑
    • LV_STATE_HOVERED 鼠标悬停(现在不支持)
    • LV_STATE_PRESSED 被按下
    • LV_STATE_SCROLLED 正在滚动
    • LV_STATE_DISABLED 禁用
      可以通过lv_obj_has_state(obj, LV_STATE_...)来判断UI对象的是否有此状态。通过lv_obj_add_state/lv_obj_clear_state添加删除状态。
  • 样式 Style
    样式lv_style_t包含诸如背景颜色、边框宽度、字体等属性来描述对象的外观。
    因为只有它们的指针保存在UI对象中,因此它们需要是静态的或全局的。并且使用前需要初始化lv_style_init(&style1).
    不同的样式可以级联,即你可以对一个UI对象同时设置多个样式。
    部分样式内容是可以继承的,如字体。
    本地样式:只对某个对象有效的样式。lv_obj_set_style_bg_color(slider1, lv_color_hex(0x2080bb), LV_PART_INDICATOR | LV_STATE_PRESSED);
    static lv_style_t style1;
    lv_style_init(&style1);
    lv_style_set_bg_color(&style1, lv_color_hex(0xa03080));
    lv_style_set_border_width(&style1, 2));
    
    lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR | LV_STATE_PRESSED);  // 样式只设置 INDICATOR的Pressed状态。 0 =  LV_PART_MAIN | LV_STATE_DEFAULT
    
  • 主题 Themes
    主题是对象的默认样式(即全局默认样式Style)。创建对象时,将自动应用来自主题的样式。
    可以在 lv_conf.h中选择要使用的主题。
  • 日志 Logging
    LVGL 有内置的 Log 模块来通知用户库中发生的事情。
    启用日志记录,请在lv_conf.h中设置LV_USE_LOG 1并将LV_LOG_LEVEL设置为以下值之一:LV_LOG_LEVEL_TRACE/INFO/WARN/ERROR/USER/NONE
    日志输出:通过 LV_LOG_TRACE/INFO/WARN/ERROR/USER(text) 函数使用日志模块.
    • 如果系统支持 printf,你只需要在 lv_conf.h 中启用 LV_LOG_PRINTF 就可以发送带有 printf 的日志。
    • 如果不能使用 printf 或者想使用自定义函数来记录日志,可以使用 lv_log_register_print_cb() 注册一个“记录器”回调。
    void my_log_cb(const char * buf)
    {
          
          
    serial_send(buf, strlen(buf));
    }
    ...
    lv_log_register_print_cb(my_log_cb);
    

对象属性

与 LVGL 的许多其他部分类似,设置坐标的概念受到 CSS 的启发。绝不是标准的完整实现,而是实现了 CSS 的子集(有时会稍作调整)。 简而言之,这意味着:

  • 设置的坐标(大小、位置、布局等)存储在样式中
  • 支持最小宽度、最大宽度、最小高度、最大高度
  • 有像素、百分比和“内容”单位。默认是像素lv_obj_set_x(btn, 10),百分比设定lv_pct(50), 按内容LV_SIZE_CONTENT
  • x=0; y=0 坐标表示父级的左上角加上左/上填充加上边框宽度
  • 宽度/高度表示全尺寸,“内容区域”较小,填充和边框宽度
  • 支持 flexbox 和网格布局的子集

带有 LV_OBJ_FLAG_HIDDENLV_OBJ_FLAG_FLOATING 的对象将被 LV_SIZE_CONTENT 计算忽略。

对象的“盒子”由以下部分构成:

  • 轮廓(outline)绘制在边界框之外。
  • 边界(bounding)框:绘制在边界(bounding)框内,元素的宽度/高度围起来的区域。
  • 边框(border)宽度:边框的宽度。
  • 填充(padding):对象两侧与其子对象之间的空间。
  • 内容(content):如果边界框按边框宽度和填充的大小缩小,则显示其大小的内容区域。
    http://lvgl.100ask.net/8.2/_images/boxmodel.png

注意:

  • LVGL 不会立即重新计算所有坐标变化。这样做是为了提高性能。 相反,对象被标记为“脏”,并且在重绘屏幕之前 LVGL 检查是否有任何“脏”对象。
  • 如果您需要获取对象的任何坐标并且坐标刚刚更改,则需要强制 LVGL 重新计算坐标。 为此调用lv_obj_update_layout(obj)
  • 如果你使用 lv_obj_set_x(obj, 20) LVGL 将 x=20 保存在对象的本地样式中。所以,如果对象的样式被删除,设置的坐标也将被删除。

对象的对齐:

  • 默认的左上角更改定位, 更改默认方式lv_obj_set_align(obj, align);
  • 设置对齐方式lv_obj_align(obj, align, x, y);
  • 与其他对象对齐lv_obj_align_to(obj_to_align, reference_obj, align, x, y);
  • LV_ALIGN是在内部对齐,还可以在外部对齐LV_ALIGN_OUT
  • lv_obj_align() 不同, lv_obj_align_to() 无法重新对齐对象,如果其坐标或参考对象的坐标发生变化

风格样式转换 Translation:

如果想在按下按钮时将其向上移动一点,一般是设置两种style:

static lv_style_t style_normal;
lv_style_init(&style_normal);
lv_style_set_y(&style_normal, 100);

static lv_style_t style_pressed;
lv_style_init(&style_pressed);
lv_style_set_y(&style_pressed, 80);

lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);

lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);

但是这样style_normal和style_pressed里面y的参数是固定的,不好重用。所以可以考虑进行相对变换:

static lv_style_t style_normal;
lv_style_init(&style_normal);
lv_style_set_y(&style_normal, 100);

static lv_style_t style_pressed;
lv_style_init(&style_pressed);
lv_style_set_translate_y(&style_pressed, -20);  // y = y - 20;

lv_obj_add_style(btn1, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn1, &style_pressed, LV_STATE_PRESSED);

lv_obj_add_style(btn2, &style_normal, LV_STATE_DEFAULT);
lv_obj_add_style(btn2, &style_pressed, LV_STATE_PRESSED);

平移实际上移动了对象。

这意味着它使滚动条和 LV_SIZE_CONTENT 大小的对象对位置变化做出反应。即UI对象本身y左边发生了变化。

但是,并不是希望所有的变化都是改变原始的值,希望是临时的变化,可以考虑 转换 transformation:

static lv_style_t style_pressed;
lv_style_init(&style_pressed);
lv_style_set_transform_width(&style_pressed, 10);
lv_style_set_transform_height(&style_pressed, 10);

lv_obj_add_style(btn, &style_pressed, LV_STATE_PRESSED);

这样按钮按下时,长宽只是临时变大10px,随后自动恢复原始大小。

Layout

分为 Flexbox(弹性伸缩盒), Grid(网格).

有一些标志可用于对象以影响它们在布局中的行为:

  • LV_OBJ_FLAG_HIDDEN 隐藏对象从布局计算中被忽略。
  • LV_OBJ_FLAG_IGNORE_LAYOUT 该对象被布局简单地忽略。它的坐标可以照常设置。
  • LV_OBJ_FLAG_FLOATINGLV_OBJ_FLAG_IGNORE_LAYOUT 相同,但带有 LV_OBJ_FLAG_FLOATING 的对象将在 LV_SIZE_CONTENT 计算中被忽略。

可以使用 lv_obj_add/clear_flag(obj, FLAG); 添加/删除这些标志

其他参考

  • Style列表与解释 https://docs.lvgl.io/master/overview/style-props.html
    pad_row/column 行/列元素之间的填充
    bg_color 背景颜色,默认0xffffff
    bg_opa 背景不透明度,0完全透明,255完全不透明。LV_OPA_10 表示10%. 默认0.

    bg_grad_color 背景渐变色
    bg_grad_dir 背景渐变色方向, LV_GRAD_DIR_NONE/HOR/VER
    bg_main_stop 背景渐变色从哪里开始,0左上,255右下,128表示中心.默认值0
    bg_grad_stop 类似main_stop但是默认值255
    bg_grad 合并BG_GRAD_COLOR BG_GRAD_DIR BG_MAIN_STOP BG_GRAD_STOP
    bg_dither_mode 背景渐变的抖动模式 LV_DITHER_NONE/ORDERED/ERR_DIFF

    bg_img_src 背景图片,可以说文件指针或者路径、数组
    bg_img_opa 背景图片透明度
    bg_img_recolor 背景图片的混合颜色,默认0x000000
    bg_img_recolor_opa 背景图片的混合颜色的强度,0表示不混合,255完全重新着色。支持LV_OPA_10
    bg_img_tiled 背景图像平铺,默认false

    img_opa/recolor/recolor_opa 前景图片的透明度和重着色

    border_color 边框颜色,默认0x000000
    border_opa 边框颜色的不透明度
    border_width 边框宽度,单位像素,默认0
    border_side 边框绘制哪一侧,支持OR操作。 LV_BORDER_SIDE_NONE/TOP/BOTTOM/LEFT/RIGHT/INTERNAL``LV_BORDER_SIDE_TOP | LV_BORDER_SIDE_LEFT
    border_post 是在子项绘制之后绘制边框? true/false

    outline_width/color/opa/pad 外轮廓的宽度等
    shadow_width/color/opa/ofs_x/ofs_y/spread 阴影的参数,偏移量,区域扩展

    line_width/dash_width/dash_gap 线状结构的线宽和虚线参数
    line_rounded 线端点的圆角
    line_color/opa 线的颜色和不透明度

    arc_width/rounded/color/opa/img_src 圆弧的宽度颜色等

    text_color/opa/font/align 文本的颜色、字体、不透明度、对齐等
    text_letter_space/line_space 文本的字母间距和行间距,单位像素
    text_decor 文本的修饰,LV_TEXT_DECOR_NONE/UNDERLINE/STRIKETHROUGH 的组合

    radius 圆角半径,单位像素。
    clip_corner 裁剪圆角上的溢出内容,默认false
    opa 按照这个值缩小所有子元素的不透明度。默认LV_OPA_COVER.
    color_filter_dsc 将一种颜色混合到对象的所有颜色
    color_filter_opa 颜色混合的强度
    anim 动画模板,指向指针lv_anim_t
    anim_time 动画持续时间,单位毫秒
    anim_speed 动画速度,单位像素/秒
    transition 过渡,lv_style_transition_dsc_t
    blend_mode 如何将颜色混合到背景LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE/MULTIPLY
    base_dir 设置对象的基本方向LV_BIDI_DIR_LTR/RTL/AUTO

  • Scroll 滚动条,具体参考 https://docs.lvgl.io/master/overview/scroll.html
    lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_...)设置对象的滚动条模式。

    • LV_SCROLLBAR_MODE_OFF从不显示滚动条
    • LV_SCROLLBAR_MODE_ON始终显示滚动条
    • LV_SCROLLBAR_MODE_ACTIVE滚动对象时显示滚动条
    • LV_SCROLLBAR_MODE_AUTO当内容大到可以滚动时显示滚动条
  • Event 事件
    任何自定义事件代码都可以通过以下方式注册uint32_t MY_EVENT_1 = lv_event_register_id();
    手动将事件发送到对象,请使用。lv_event_send(obj, <EVENT_CODE> &some_data)

    /*Simulate the press of the first button (indexes start from zero)*/
    uint32_t btn_id = 0;
    lv_event_send(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);
    

    LV_EVENT_REFRESH是一个特殊事件,因为它旨在让用户通知对象自行刷新。一些例子:

    • 通知标签根据一个或多个变量(例如当前时间)刷新其文本
    • 语言更改时刷新标签
    • 如果满足某些条件(例如,输入了正确的 PIN),则启用按钮
    • 在超出限制时向对象添加/删除样式等
      lv_event_t是传递给事件回调的唯一参数,它包含有关事件的所有数据。可以从中获取以下值:
    • lv_event_get_code(e)获取事件代码
    • lv_event_get_current_target(e)获取向其发送事件的对象。即正在调用其事件处理程序的对象。
    • lv_event_get_target(e)获取最初触发事件的对象(启用不同的 Fromif事件冒泡lv_event_get_target
    • lv_event_get_user_data(e)获取作为最后一个参数传递的指针。lv_obj_add_event_cb
    • lv_event_get_param(e)获取作为最后一个参数传递的参数lv_event_send
      事件冒泡, 启用LV_OBJ_FLAG_EVENT_BUBBLE的UI会所有事件也将发送到对象的父级lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE)
    static void event_cb(lv_event_t * e)
    {
          
          
        /*The original target of the event. Can be the buttons or the container*/
        lv_obj_t * target = lv_event_get_target(e);
    
        /*The current target is always the container as the event is added to it*/
        lv_obj_t * cont = lv_event_get_current_target(e);
    
        /*If container was clicked do nothing*/
        if(target == cont) return;
    
        /*Make the clicked buttons red*/
        lv_obj_set_style_bg_color(target, lv_palette_main(LV_PALETTE_RED), 0);
    }
    
    /**
    * Demonstrate event bubbling
    */
    void lv_example_event_3(void)
    {
          
          
    
        lv_obj_t * cont = lv_obj_create(lv_scr_act());
        lv_obj_set_size(cont, 290, 200);
        lv_obj_center(cont);
        lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW_WRAP);
    
        uint32_t i;
        for(i = 0; i < 30; i++) {
          
          
            lv_obj_t * btn = lv_btn_create(cont);
            lv_obj_set_size(btn, 80, 50);
            lv_obj_add_flag(btn, LV_OBJ_FLAG_EVENT_BUBBLE);
    
            lv_obj_t * label = lv_label_create(btn);
            lv_label_set_text_fmt(label, "%"LV_PRIu32, i);
            lv_obj_center(label);
        }
    
        lv_obj_add_event_cb(cont, event_cb, LV_EVENT_CLICKED, NULL);
    }
    
  • Input 输入设备 https://docs.lvgl.io/master/overview/indev.html
    设置光标

    lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv);
    
    LV_IMG_DECLARE(mouse_cursor_icon);                          /*Declare the image source.*/
    lv_obj_t * cursor_obj = lv_img_create(lv_scr_act());       /*Create an image object for the cursor */
    lv_img_set_src(cursor_obj, &mouse_cursor_icon);             /*Set the image source*/
    lv_indev_set_cursor(mouse_indev, cursor_obj);               /*Connect the image  object to the driver*/
    

    手势 LV_EVENT_GESTURE, 与触摸屏交互产生,一般不怎么用
    键盘类设备

    • 如果键盘类设备想要类似Tab捕获焦点,必须有一个组。需要将输入设备与组关联。
    • 一个输入设备只能向一个组发送key事件,但一个组可以从多个输入设备接收数据。
    • 交互式小部件(如按钮、复选框、滑块等)可以自动添加到默认组中。
      只需创建一个组,然后使用lv_group_t * g = lv_group_create();``lv_group_set_default(g);
      不要忘记将一个或多个输入设备分配给默认组。 lv_indev_set_group(my_indev, g);
    • 有一些预定义的键具有特殊含义:
      • LV_KEY_NEXT专注于下一个对象
      • LV_KEY_PREV专注于上一个对象
      • LV_KEY_ENTER触发器等。事件LV_EVENT_PRESSED/CLICKED/LONG_PRESSED
      • LV_KEY_UP增加价值或向上移动
      • LV_KEY_DOWN降低值或向下移动
      • LV_KEY_RIGHT增加价值或向右移动
      • LV_KEY_LEFT减小值或向左移动
      • LV_KEY_ESC关闭或退出(例如,关闭下拉列表)
      • LV_KEY_DEL删除(例如,文本区域中右侧的字符)
      • LV_KEY_BACKSPACE删除左侧的字符(例如,在文本区域中)
      • LV_KEY_HOME转到开头/顶部(例如,在文本区域中)
      • LV_KEY_END转到末尾(例如,在文本区域中)
  • 颜色
    RGB颜色 lv_color_t c = lv_color_make(red, green, blue); lv_color_t c = lv_color_hex(0x123456);
    HSV颜色 lv_color_t c = lv_color_hsv_to_rgb(h, s, v); lv_color_hsv_t c_hsv = lv_color_rgb_to_hsv(r, g, b); lv_color_hsv_t c_hsv = lv_color_to_hsv(color);
    Palette 调色板,可以使用命名颜色以及4个更深的和5个更浅的变体
    使用方式:lv_color_t c = lv_palette_main(LV_PALETTE_...); lv_palette_lighten(LV_PALETTE_..., v); lv_palette_darken(LV_PALETTE_..., v)

    • LV_PALETTE_RED
    • LV_PALETTE_PINK
    • LV_PALETTE_PURPLE
    • LV_PALETTE_DEEP_PURPLE
    • LV_PALETTE_INDIGO
    • LV_PALETTE_BLUE
    • LV_PALETTE_LIGHT_BLUE
    • LV_PALETTE_CYAN
    • LV_PALETTE_TEAL
    • LV_PALETTE_GREEN
    • LV_PALETTE_LIGHT_GREEN
    • LV_PALETTE_LIME
    • LV_PALETTE_YELLOW
    • LV_PALETTE_AMBER
    • LV_PALETTE_ORANGE
    • LV_PALETTE_DEEP_ORANGE
    • LV_PALETTE_BROWN
    • LV_PALETTE_BLUE_GREY
    • LV_PALETTE_GREY
      颜色存储的变量:(配置默认颜色类型见 lv_conf.h的LV_COLOR_DEPTH)
    • lv_color1_t单色。为了兼容,还有 R、G、B 字段,但它们始终是相同的值(1 字节)
    • lv_color8_t用于存储 8 位颜色(1 字节)的 R(3 位)、G(3 位)、B(2 位)组件的结构
    • lv_color16_t用于存储 R(5 位)、G(6 位)、B(5 位)组件的结构,用于存储 16 位颜色(2 字节)
    • lv_color32_t用于存储 R(8 位)、G(8 位)、B(8 位)组件的 24 位颜色(4 字节)的结构
    • lv_color_t等于取决于配置的颜色深度设置lv_color1/8/16/24_t
    • lv_color_int_t uint8_t,或取决于颜色深度设置。用于从纯数字构建颜色数组。
  • 字体
    LVGL 支持UTF-8编码的 Unicode 字符。
    字体具有bpp(每像素位数)属性。它显示使用多少位来描述字体中的像素。
    可能的bpp值为 1、2、4 和 8(值越高意味着质量越好)。bpp属性还会影响存储字体所需的内存量。例如,bpp = 4使字体比bpp = 1 大近四倍。
    普通字体:

    • 包含所有 ASCII 字符、度数符号 (U+00B0)、项目符号 (U+2022) 和内置符号.
    • 大小不同 LV_FONT_MONTSERRAT_12/14/16/18/20/22/24/26/28/30/32/34/36/38/40/42/44/46/48
      特殊字体:
    • LV_FONT_MONTSERRAT_12_SUBPX与普通 12 像素字体相同,但具有亚像素渲染
    • LV_FONT_MONTSERRAT_28_COMPRESSED与普通 28 像素字体相同,但存储为 3 bpp 的压缩字体
    • LV_FONT_DEJAVU_16_PERSIAN_HEBREW16 px 字体,正常范围 + 希伯来语、阿拉伯语、波斯语字母及其所有形式
    • LV_FONT_SIMSUN_16_CJK16 px 字体,正常范围加上 1000 个最常见的 CJK 部首
    • LV_FONT_UNSCII_88 像素完美字体,仅包含 ASCII 字符
    • LV_FONT_UNSCII_1616 像素的完美字体,只有 ASCII 字符
      BPP=4的内置字体还包含了符号字体,可以单独、联合使用lv_label_set_text(my_label, LV_SYMBOL_OK); lv_label_set_text(my_label, LV_SYMBOL_OK "Apply");
      https://docs.lvgl.io/master/_images/symbols.png
  • 输入法
    默认的输入法不支持中文,需要单独使用中文字体和拼音输入法的组合。

  • 图像
    支持各种内置颜色格式:

    • LV_IMG_CF_TRUE_COLOR只需存储 RGB 颜色(LVGL 配置的任何颜色深度)。
    • LV_IMG_CF_TRUE_COLOR_ALPHA喜欢但它也为每个像素添加一个字母(透明度)字节。LV_IMG_CF_TRUE_COLOR
    • LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED喜欢但是如果一个像素有颜色(以_lv_conf.h_ 设置),它将是透明的。LV_IMG_CF_TRUE_COLOR``LV_COLOR_TRANSP
    • LV_IMG_CF_INDEXED_1/2/4/8位使用具有 2、4、16 或 256 种颜色的调色板,并以 1、2、4 或 8 位存储每个像素。
    • **LV_IMG_CF_ALPHA_1/2/4/8BIT****仅存储 1、2、4 或 8 位的 Alpha 值。**像素采用颜色和设置的不透明度。源图像必须是 Alpha 通道。这非常适合类似于字体的位图,其中整个图像是一种可以更改的颜色。style.img_recolor
      使用图像数据的代码:
    uint8_t my_img_data[] = {
          
          0x00, 0x01, 0x02, ...};
    
    static lv_img_dsc_t my_img_dsc = {
          
          
        .header.always_zero = 0,
        .header.w = 80,
        .header.h = 60,
        .data_size = 80 * 60 * LV_COLOR_DEPTH / 8,
        .header.cf = LV_IMG_CF_TRUE_COLOR,          /*Set the color format*/
        .data = my_img_data,
    };
    

    使用在线转换器得到的bin文件代码:

    lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);
    /*From variable*/
    LV_IMG_DECLARE(my_icon_dsc);  // 声明图片
    lv_img_set_src(icon, &my_icon_dsc);
    /*From file*/
    lv_img_set_src(icon, "S:my_icon.bin");
    
  • 动画animations https://docs.lvgl.io/master/overview/animation.html
    动画函数原型void func(void * var, lv_anim_var_t value);
    一个全面的Demo:

    /* INITIALIZE AN ANIMATION
    *-----------------------*/
    
    lv_anim_t a;
    lv_anim_init(&a);
    
    /* MANDATORY SETTINGS
    *------------------*/
    
    /*Set the "animator" function*/
    lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) lv_obj_set_x);
    
    /*Set target of the animation*/
    lv_anim_set_var(&a, obj);
    
    /*Length of the animation [ms]*/
    lv_anim_set_time(&a, duration);
    
    /*Set start and end values. E.g. 0, 150*/
    lv_anim_set_values(&a, start, end);
    
    /* OPTIONAL SETTINGS
    *------------------*/
    
    /*Time to wait before starting the animation [ms]*/
    lv_anim_set_delay(&a, delay);
    
    /*Set path (curve). Default is linear*/
    lv_anim_set_path(&a, lv_anim_path_ease_in);
    
    /*Set a callback to indicate when the animation is ready (idle).*/
    lv_anim_set_ready_cb(&a, ready_cb);
    
    /*Set a callback to indicate when the animation is deleted (idle).*/
    lv_anim_set_deleted_cb(&a, deleted_cb);
    
    /*Set a callback to indicate when the animation is started (after delay).*/
    lv_anim_set_start_cb(&a, start_cb);
    
    /*When ready, play the animation backward with this duration. Default is 0 (disabled) [ms]*/
    lv_anim_set_playback_time(&a, time);
    
    /*Delay before playback. Default is 0 (disabled) [ms]*/
    lv_anim_set_playback_delay(&a, delay);
    
    /*Number of repetitions. Default is 1. LV_ANIM_REPEAT_INFINITE for infinite repetition*/
    lv_anim_set_repeat_count(&a, cnt);
    
    /*Delay before repeat. Default is 0 (disabled) [ms]*/
    lv_anim_set_repeat_delay(&a, delay);
    
    /*true (default): apply the start value immediately, false: apply start value after delay when the anim. really starts. */
    lv_anim_set_early_apply(&a, true/false);
    
    /* START THE ANIMATION
    *------------------*/
    lv_anim_start(&a);                             /*Start the animation*/
    

基础内容到此结束,其他内容参考官方文档。

后续针对控件和使用组合进行单独实例学习。

猜你喜欢

转载自blog.csdn.net/bbdxf/article/details/127629514