本来对GUI编程有一些基础,然后参照网上LVGL的琐碎代码,也可以做出来一些小界面,但对于很多概念还是很模糊,故开此笔记对LVGL官方文档进行学习记录,以便于搞清一些基本概念和操作方法。

 工作流

LVGL数据流

     用户APP通常包括两个逻辑:UI逻辑和时间逻辑,UI逻辑表示用户创建了哪些控件,并对这些控件做了哪些样式和属性的修改,对这些控件做了哪些事件的绑定。时间逻辑用于向LVGL提供时间基准。

(1) 数据流

    LVGL内部在时间基准的驱动下,通过lv_timer_handler()这个函数对整个图形界面进行更新。首先决定哪些控件需要被渲染(例如,E,G,H)。然后渲染逻辑负责进行渲染把控件由逻辑形态转化成像素形态,放进缓冲区,最后写进LCD面板的帧缓冲区。

(2) 事件流

Lvgl事件流

     事件触发的源头是输入设备,一次按键点击,一次触摸点击。输入设备驱动将原始的硬件输入转换成lvgl内部格式(lv_indev_data_t )。输入管理将lv_indev_data_t 中的输入内容(坐标,按键)转化成事件(单击,双击)。并将这些事件插入队列进行排队处理,在时间基驱动下定时处理。然后,事件目标定位通过坐标或者是当前聚焦项确定是哪个控件响应事件。最后,就会调用该控件的事件回调函数,处理业务逻辑,并进行UI更新,最终触发渲染更新。这就是事件驱动GUI的基本过程。

 显示设备 vs 屏幕 vs 层

     LVGL 的显示系统通过 显示设备(Display)、层(Layers)、屏幕(Screen) 三者配合,实现「多设备支持、分层渲染、多 UI 页面切换」的能力,关系可总结为:

  • Display:硬件显示的抽象(如 TFT 屏),是 LVGL 与物理屏幕交互的 “桥梁”,支持多图层叠加。
  • Layers:Display 内的逻辑分层(优先级从低到高:底层→活跃 Screen 层→顶层→系统层),上层内容可覆盖下层。
  • Screen:UI 页面的 “根控件”,需挂载到某一层(通常是「活跃 Screen 层」),同一时刻一个层内仅一个 Screen “活跃显示”。

显示设备(Display):硬件的抽象载体

  • 作用:代表实际显示硬件(如 TFT/LCD 屏),负责 “缓冲区→物理屏幕” 的数据推送。
  • 多设备支持:LVGL 可同时管理多个 Display(如双屏显示场景),每个 Display 独立配置分辨率、刷新回调等。
  • 关键 API
    // 创建 Display(指定分辨率)
    lv_display_t *disp = lv_display_create(480, 320);
    // 绑定“缓冲区→硬件”的刷新回调(需用户实现硬件驱动逻辑)
    lv_display_set_flush_cb(disp, my_display_flush);
    // 获取默认 Display(单屏场景可直接用)
    lv_display_t *default_disp = lv_display_get_default();
    

屏幕(Screen):UI 页面的 “根节点”

1.创建

    Screen 是控件树的根节点(本质是特殊控件),代表一个 “独立 UI 页面”,核心特点:调用控件创建函数时,父对象传 NULL 即可创建 Screen(可基于 lv_objlv_image 等控件实现):

// 示例1:用基础控件创建“空白页面”
lv_obj_t *scr_main = lv_obj_create(NULL);

// 示例2:用图像控件创建“带背景图的页面”
lv_obj_t *scr_bg = lv_image_create(NULL);
lv_image_set_src(scr_bg, "S:/bg_img.bin"); // 设置背景图像
2. 活跃与切换

同一时刻,Display 的「活跃 Screen 层」仅能显示 一个活跃 Screen,切换需用专用 API:

  • 带动画切换:
    // 淡入动画切换,时长500ms,无延迟,不自动删除旧 Screen
    lv_screen_load_anim(scr_new, LV_SCREEN_LOAD_ANIM_FADE, 500, 0, false);
    
  • 自动删除旧 Screen:
    // 切换后自动删除原活跃 Screen(节省内存)
    lv_screen_load_anim(scr_new, LV_SCREEN_LOAD_ANIM_SLIDE_LEFT, 500, 0, true);
    
3. 限制与删除
  • Screen 会自动铺满对应 Display,无法手动修改尺寸(lv_obj_set_size)或位置(lv_obj_set_pos)。
  • 不能直接删除活跃中的 Screen,需先切换到其他 Screen,再用 lv_obj_delete(scr_old) 删除。

层(Layers):分层渲染

每个 Display 内置 4 个逻辑层(优先级从低到高),上层可覆盖下层,适合不同场景:

层级 优先级 典型场景
底层(Bottom) 最低 显示背景级内容(如视频、底图)
活跃 Screen 层 显示当前活跃 Screen 的 UI 内容
顶层(Top) 次高 显示临时弹窗(如提示框、半透菜单)
系统层(System) 最高 显示系统级覆盖(如状态栏、紧急提示)

获取层的 API

lv_display_t *disp = lv_display_get_default();
lv_obj_t *layer_bottom = lv_display_get_layer_bottom(disp);   // 底层
lv_obj_t *layer_screen = lv_display_get_screen_active(disp); // 活跃Screen所在层
lv_obj_t *layer_top = lv_display_get_layer_top(disp);        // 顶层
lv_obj_t *layer_sys = lv_display_get_layer_sys(disp);        // 系统层

应用

  1. 多 Screen 切换(空间换时间):若需频繁切换 UI 页面(如 “主界面→设置→关于”),可提前创建所有 Screen 并保存在 RAM 中,切换时用 lv_screen_load 快速切换 —— 避免重复创建控件树的开销,用内存换性能。

  2. 分层叠加(场景化显示)

    • 视频播放:底层显示视频,活跃 Screen 层显示 “播放控制条”,顶层备用 “暂停弹窗”;
    • 车载 UI:底层显示地图,活跃 Screen 层显示 “导航控件”,系统层显示 “车速状态栏”。

控件(Widget)

     控件是图形界面的核心,APP使用控件构建静态和动态显示以及人机交互。包括进度条,按钮,标签,复选框。APP创建控件树,lvgl就会渲染并显示出来这些控件。

基础控件(Base Widget)

        基础控件:是拥有基本特性的控件,其他所有控件都基于基础控件又添加了一些特性。对了这里补充一点,基础控件不仅被当做根节点使用,它还被当做容器使用,把几个控件进行组合。

//创建水平容器
lv_obj_t * cont_row = lv_obj_create(parent);
lv_obj_set_size(cont_row, 210, 25);
lv_obj_align(cont_row, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_flex_flow(cont_row, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(cont_row, LV_FLEX_ALIGN_SPACE_AROUND, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
	
//创建文本标签
lv_obj_t *label = lv_label_create(cont_row);  
lv_label_set_text(label, txt); 
lv_obj_set_style_text_font(label, &lv_font_montserrat_12, 0);
	
//创建滑块
lv_obj_t* slider = lv_slider_create(cont_row);
lv_obj_set_size(slider, 100, 5);
lv_slider_set_range(slider, min, max); 
lv_slider_set_value(slider, val, LV_ANIM_OFF);
	
运行结果
运行结果

如上面代码所示,使用基础对象最为容器,把标签和滑块组合成一个整体。

基础属性 VS 特有属性

基础属性:每个控件都有的属性Position,Size,Parent,Styles,Events it emits,Flags like ClickableScollable, etc.,Etc.

lv_obj_set_size(btn1, 100, 50);  
lv_obj_set_pos(btn1, 20,30);  

如上代码,使用lv_obj_set可以设置这些基本属性,使用lv_obj_get可以获得这些属性,这些函数可以作用于所有的控件。

控件所独有的属性:比如滚动条(slider)拥有maxvalue,minvalue,current value。

lv_slider_set_range(slider1, 0, 100);               
lv_slider_set_value(slider1, 40, LV_ANIM_ON);       

上面的函数可以进行这些属性的设置,这些函数是滚动条独有的函数,只能作用于滚动条。

 控件的创建和删除

     在lvgl运行过程中,所有的控件对象都可以被动态地创建和删除。这使得APP可以在按钮按下时,可以动态地创建一个Screen,然后并加载这个Screen到显示设备上。在不需要的时候这个Screen删除掉,然后并创建其他Screen,以节省内存。

lv_obj_t * lv_<widget>_create(lv_obj_t * parent, <other parameters if any>);

如上,每一个控件都有其独特的创建函数,传入父对象,以及其他属性参数。

void lv_obj_delete(lv_obj_t * widget);//立即删除
void lv_obj_delete_async(lv_obj_t *obj);//异步删除
void lv_obj_delete_delayed(lv_obj_t *obj, uint32_t delay_ms);//延迟删除

删除的时候都用同一函数删除,分别为立即删除,异步删除和延迟删除函数。异步删除是在lvgl的下一个处理周期再进行删除,应用场景:比如说,要在一个控件的回调函数里删除父控件,则不能立即删除(这里我也不理解是什么意思)。延时删除就是等一个时间再删除。void lv_obj_clean(lv_obj_t *obj)可以清除一个父控件的所有子对象控件。注意在删除一个控件之前将其指针指向空。

父控件 VS 子控件

   除了Screen以外,我们创建其他所有的控件必须有父对象,通过创建函数传入。使用 lv_obj_get_parent(widget)可以获取一个控件的父对象;使用 lv_obj_set_parent(widget)(widget, new_parent) 可以设置一个控件的父对象;③ 使用 lv_obj_get_child(parent,idx) 可以获得一个控件的子对象。idx传入0获得第一个创建的子对象,传入1获得第二个创建的子对象。传入-1获得最后一次创建的子对象。

uint32_t i;
for(i = 0; i < lv_obj_get_child_count(parent); i++) {
    lv_obj_t * child = lv_obj_get_child(parent, i);
    /* Do something with child. */
}

     可以使用上述代码遍历一个控件的所有子对象。 lv_obi_get_index(widget) 可以返回一个控件在它父控件中的索引,也就是说我们 可以知道这个控件是第几个创建的。 lv_obi_move_foreground(widget) 和 lv_obi_move_background(widget) 可以将控件分别放到前景或者背景。 使用 lv_obj_move_index(widget,index) 可以移动一个控件在其父控件中的索引位置。使用lv_obj_swap(widgte1,widget2)可以交换两个控件的位置。使用lv_obj_get_screen(widget) 可以获取根节点控件即SCreen。

     父对象可以被看做子对象的一个容器,主要表现在3个方面:① 子对象的尺寸超过了父对象将会被裁剪。② 父对象移动,子对象会跟着移动。③ 子对象被删除父对象还存在,父对象被删除其所有子对象必然会被删除。任何的控件都可以当做子对象也可以当做父对象,但是有些常用的父子控件搭配:

    lv_obj_t * btn1 = lv_button_create(lv_screen_active());
    lv_obj_t * label = lv_label_create(btn1);
    lv_label_set_text(label, "按钮");

    lv_obj_align(btn1, LV_ALIGN_CENTER,0,0);
    lv_obj_center(label);

如上图就是标签常常用作按钮的子控件,以标识按钮的名字。

此小结只讲基础控件的特性,即阐述所有控件所通用的特性和概念。

      按钮,滚动条,标签啦等各种控件的创建函数不同,但都返回一个 lv_obj_t,利用这个指针可以完成对控件属性的设置,比如风格,事件回调函数等。基础控件通俗第来说就是一个矩形,拥有所有控件的基本特性。用面向对象的观点看:基本控件是所有控件的父类。所有用于基础控件的函数都可用于其他控件,例如 lv_obj_set_width(slider,100)

部件(Parts)

    一个控件由一个部件或者多个部件组成,比如:一个按钮只有一个部件,叫做LV_PART_MAIN。一个滑动条有三个部件:LV_PART_MAIN,LV_PART_INDICATOR,LV_PART_KNOB。使用部件可以对一个控件的子元素风格进行单独设置,或使用特定的子元素触发回调函数。常见部件如下:

常见部件

 状态(States)

指的是一下单一状态的组合

常见状态

  选中状态与聚焦状态的区别:聚焦是针对整个控件来说的,比如使用鼠标滑过不同的按钮,这几个按钮就会依次被聚焦,聚焦到哪个按钮哪个按钮就可以被点击。而选中指的是控件子元素的选中,比如选中复选框里面的某个选项。

lv_obj_has_state(widget, LV_STATE_...)

以上API用于判断按钮处于哪个状态。

lv_obj_add_state(widget, LV_STATE_...);
lv_obj_remove_state(widget, LV_STATE_...);

以上API用于给控件添加控件或者移除控件的某个状态。

        这里一定要搞清楚状态与事件的区别,他们不是一个东西,控件只有在某些状态下才会发送事件,调用回调函数。比如按钮按下状态的一瞬间会发送事件,然后滚动条滚动状态也会发送事件。

风格(Styles)

     风格服务GUI系统的静态和动态显示。前面的事件和状态是为了人机交互,那么风格就是为了美观。我们都知道,控件有各种属性:背景,前景,边界宽度,字体等。风格就是这些属性值的集合,用来设置这些属性。风格以风格对象(lv_style_t)的形式在MCU内存中存在,方便我们快速设置不同控件的属性。

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(obj, &style, 0);

      其使用流程为上:创建风格对象--->设置属性---->给控件添加风格! LVGL 风格的设置灵活且强大:

lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR | LV_STATE_PRESSED);
lv_obj_add_style(slider1, &style1, LV_PART_INDICATOR); 
lv_obj_add_style(btn1, &style1, 0); 

   ① 为一个控件的某个部件的某个状态设置风格,|左边为部件右边为状态。如上代码,滑动条的指示器(INDICATOR)被按下使用style1(第一行)。如果不传入状态参数那么就是默认状态(LV_STATE_DEFAULT)(第二行)。如果传入0则表示主体LV_PART_MAIN部件的默认状态(第三行)。

   ② 风格可以级联,可以往一个控件的不同部件或状态分别添加风格。

static lv_style_t style1,style2;
lv_obj_t * slider = lv_slider_create(lv_screen_active());(lv_screen_active());

lv_style_init(&style1);
lv_style_set_border_color(&style1, lv_color_hex(0xFF0000));
lv_style_set_border_width(&style1, 4);

lv_style_init(&style2);
lv_style_set_border_color(&style2, lv_color_hex(0x00FF00));
lv_style_set_border_width(&style2, 4);

lv_obj_add_style(slider, &style1, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_add_style(slider, &style2,LV_PART_KNOB|LV_STATE_PRESSED);;

    如上述代码,可以为slider的主体默认状态设置style1,为指示点的按下状态设置style2。

(9) 主题(thems)

    主题是风格的集合,一种主题使用在审美上相容的风格去设置不同控件。以上就是lvgl一些核心的概念的简介,接下来将对基础控件进行详细讲解。

标志(Flags)

   使用标志可以用于控制控件的某些特性。

/* Hide on Widget */
lv_obj_add_flag(widget, LV_OBJ_FLAG_HIDDEN);

/* Make a Widget non-clickable */
lv_obj_remove_flag(widget, LV_OBJ_FLAG_CLICKABLE);

      使用上述API可以添加隐藏标志LV_OBJ_FLAG_HIDEN使得控件隐藏,删除点击标志位LV_OBJ_FLAG_CLICKABLE让控件变得单击无效。下面还有一些标志位:

常见标志

 输入设备VS事件

输入事件 

      事件是一种机制用来服务GUI系统的人机交互事件用来通知APP 控件发生了什么(比如控件的移动,点击,释放,删除),然后APP使用回调函数来写事件处理函数。如下所示为事件-回调函数编程模型,跟中断-服务函数编程模型类似。


 //按键回调函数
void event_handler(lv_event_t* event)
{
  int code = lv_event_get_code(event);//获取事件类型的代码
  lv_obj_t* obj=lv_event_get_target(event);//获取事件的对象的地址
  lv_obj_t* data=lv_event_get_user_data(event);//获取传输的数据
  printf("data:%s\n",data);
  if(code == LV_EVENT_CLICKED)
  {
    printf("this is clicked event\n");//判断是否是点击事件
  }
}


//按键Demo
void demo_button(){
  char *data = "abcdefg";//要传入的数据
  lv_obj_t* screen=lv_scr_act();
  lv_obj_t* button=lv_btn_create(screen);
  lv_obj_t* label=lv_label_create(button);//创建一个文本对象并将按键对象添加进去
  lv_label_set_text(label,"Hello");//添加一个文本
  lv_obj_center(button);
  //1,按钮控件名  2,回调函数 3,监听什么事件 4,传入什么数据
  lv_obj_add_event_cb(button,event_handler,LV_EVENT_CLICKED,data);
}

      如上代码  ,lv_obj_add_event_cb(widget,evnthandler,event_type,data)用于给控件添的事件,添加回调函数。其可以传入4个参数,前两个分别为控件和其对应的回调函数。后面是事件类型和要往回调函数内传输的数据,在回调函数内:使用 lv_event_get_code(event) 获取事件类型,同一控件的不同事件可以绑定同一个回调函数。使用lv_event_get_target(event);来获取调用此回调函数的控件对象,不同控件可以绑定同一个回调函数(call_back);使用lv_event_get_user_data(event);来获取要传递给回调函数的数据(以地址的方式传送)。那么具体都有哪些事件呢?

      顾名思义即输入设备触发的事件,比如用手指点击触摸屏,滑动触摸屏,使用鼠标点击,滚动鼠标滚轮等输入设备所触发的事件。支持的事件很多,牛逼的是居然支持触摸屏手势检查。 绘图事件和其他事件这个我不大理解就不往上写了。

输入设备事件

事件发送

      使用 lv_obj_send_event(obj, <EVENT_CODE>, &some_data) 手动发送事件到对象。例如,这可以用于通过模拟按钮按下来手动关闭消息框。

/*模拟第一个按钮的按下(索引从零开始)*/
uint32_t btn_id = 0;
lv_obj_send_event(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);

      对于显示器和输入设备也同样适用: lv_display_send_event(obj, <EVENT_CODE>, &some_data) 和 lv_indev_send_event(obj, <EVENT_CODE>, &some_data)。

刷新事件

      LV_EVENT_REFRESH 是一个特殊事件,用户可以使用这个事件通知控件刷新自身。例如,通知标签根据一个或多个变量(例如当前时间)刷新其文本。一般都是LVGL内部自动周期调用。

 事件的字段

     lv_event_t * e 是传递给事件回调函数的唯一参数,它包含了该事件的所有数据。可以从中获取以下值:

事件字段的获取

事件冒泡

      如果启用了 lv_obj_add_flag(widget, LV_OBJ_FLAG_EVENT_BUBBLE),则所有事件也将发送给Widget的父级。如果父级也启用了 LV_OBJ_FLAG_EVENT_BUBBLE,那么事件将被发送给它的父级,依此类推。使用 lv_event_get_current_target_obj(e)获取的当前控件,即触发此回调函数的的控件。要获取最初的触发控件,可以在事件处理程序中调用lv_event_get_target_obj(e)。

布局

弹性布局

术语

flex_flow

   使用以下函数设置和控制任何父控件上的Flex布局,使用以下函数进行布局设置:设置接口 lv_obj_set_flex_flow(obj, flex_flow)其中 flex_flow 的值可以是:

flex-wrap
列换行
行换行

  flex_align

     使用 lv_obj_set_flex_align(obj, main_place, cross_place, track_cross_place),来管理子对象的对齐。

main_place: 定义子元素在主轴方向上的对齐方式。 例如。 LV_FLEX_FLOW_ROW_WRAP 上的元素向右刷新。(它在 CSS 中称为 justify-content )

cross_place:定义子元素在交叉轴的对齐方式。 例如。 如果元素具有不同的高度,则将它们放置在轨道的底部。(在 CSS 中称为 align-items )

track_cross_place: 定义多行元素在交叉轴的对齐方式(在 CSS 中称为 align-content )

取值为:

示例:

main_place
cross_place
track_cross_place
Flex_grow

      Flex grow(弹性增长)使得子对象增长,以填充满轨道上的可用控件。当很多个子对象都有生长参数时,可用空间将按比例分配给生长值。可以使用 lv_obj_set_flex_grow(child, value) 在子节点上设置 Flex 增长值。

每个元素使用不同的增长值

(1) 要修改对象之间的间距,可以在 flex 容器上设置以下样式属性:

  • pad_row 设置行之间的内边距。

  • pad_column 设置列之间的内边距。

     使用 lv_style_set_pad_column(&row_container_style, 0)修改对象之间的间距,可以在 flex 容器上设置以下样式属性。

(2) 可以使用接口 lv_obj_add_flag(child, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK) 强制 Flex 将元素放入新行。

网格布局

术语

  网络描述符 

       要在父级上设置描述符,使用 lv_obj_set_grid_dsc_array (widget, col_dsc, row_dsc)。

       使用两个数组来描述网络,一个描述行的个数以及每行的大小,一个描述列的个数以及每列的大小。 数组的最后一个元素必须为:LV_GRID_TEMPLATE_LAST。如下:

static int32_t column_dsc[] = {100, 400, LV_GRID_TEMPLATE_LAST};/* 2 列,宽度分别为 100 像素和 400 像素 */
static int32_t row_dsc[] = {100, 100, 100, LV_GRID_TEMPLATE_LAST};/* 3 行,高度分别为 100 像素 */

    除了设置像素大小外,还可以使用两个特殊值:

LV_GRID_CONTENT 设置大小以适应轨道;

LV_GRID_FR(X) 确定使用剩余空间的大小。值越大,占用的空间越大;

网络项

默认情况下,子对象不会添加到网格中。需要手动将它们添加到单元格中,使用

 lv_obj_set_grid_cell(child, column_align, column_pos, column_span, row_align, row_pos, row_span) 进行添加。

column_align 和 row_align 决定了子小部件在其单元格中的对齐方式。可能的值有:

column_span 和 row_span 表示从起始单元格开始应该占据多少轨道。必须是 >= 1。

Grid align(对齐方式)

        使用 lv_obj_set_grid_align (widget, column_align, row_align) 设置轨道的对齐方式,

如果有一些空余空间,Grid 轨道中的项(Widgets)可以通过以下几种方式对齐:

Sub grid(子网格)

        如果您将小部件的列或行网格描述符设置为NULL,它将使用其父级的网格描述符。

   lv_obj_t * cont_child = lv_obj_create(cont);
   lv_obj_set_style_grid_column_dsc_array(cont_child, NULL, 0);
   lv_obj_set_style_grid_row_dsc_array(cont_child, NULL, 0);

滚动

        如果一个控件超过了其父对象的范围,其父对象就变得可滚动。子控价可以在一次滑动中水平或垂直滚动。

滚动模式

使用lv_obj_set_scrollbar_mode(widget, LV_SCROLLBAR_MODE_...)可以为Widget设置滚动条模式。

滚动样式

      滚动条是控件的一个特殊部件,LV_PART_SCROLLBAR。可以通过以下代码将滚动条设置为红色:

static lv_style_t style_red;
lv_style_init(&style_red);
lv_style_set_bg_color(&style_red, lv_color_red());
lv_obj_add_style(widget, &style_red, LV_PART_SCROLLBAR);

     当控件正在被滚动时,会进入LV_STATE_SCROLLED状态。我们可以在滚动期间,为其设置不同样式。例如,以下代码会在Widget滚动时将滚动条设置为蓝色:

static lv_style_t style_blue;
lv_style_init(&style_blue);
lv_style_set_bg_color(&style_blue, lv_color_blue());
lv_obj_add_style(widget, &style_blue, LV_STATE_SCROLLED | LV_PART_SCROLLBAR);

滚动事件

以下事件与滚动相关:

滚动效果

     可以使用lv_obj_remove_flag(widget, LV_OBJ_FLAG_SCROLLABLE)使控件不可滚动。滚动发生的方向可以通过lv_obj_set_scroll_dir(widget, LV_DIR_...)进行控制。以下是可用的方向值:

滚动链&滚动惯性

       如果一个对象无法进一步滚动(例如已经到达最底部位置),额外的滚动将传递给其父对象。如果在该方向上可以滚动父对象,则父对象将被滚动。它会继续传递给祖父和曾祖父对象。滚动传播被称为“滚动链”,可以使用  LV_OBJ_FLAG_SCROLL_ELASTIC 标志来启用/禁用它。如果禁用了链式滚动,传播将在该对象处停止,并且父对象(们)将不会滚动。

      当用户滚动一个Widget并释放时,LVGL可以模拟滚动的惯性动量。就像Widget被“抛出”一样,滚动会平滑地减速。可以通过LV_OBJ_FLAG_SCROLL_MOMENTUM`标志启用或禁用滚动动量。

对齐(snap)

   当滚动结束时,Widget的子对象可以根据特定规则对齐(snap)。子对象可以通过设置LV_OBJ_FLAG_SNAPPABLE标志单独启用snap功能。控件可以以以下四种方式对齐其子对象:

可以通过以下方法设置snap对齐方式:lv_obj_set_scroll_snap_x(widget, LV_SCROLL_SNAP_...):设置水平方向的snap。 lv_obj_set_scroll_snap_y(widget, LV_SCROLL_SNAP_...)设置垂直方向的snap。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐