LVGL基础对象的框架、思维与概念,以及部分源码解析(屏幕篇,注:本篇源码较多)

        书接上回,讲控件的结构,那就肯定绕不开所有控件的祖先,也是一切的开始,整个屏幕对象。

        在LVGL当中我们可以通过lv_scr_act()函数来获取当前正在显示的屏幕对象,我们查看该函数,会发现他是通过lv_disp_get_default()(注:这是一个获取当前显示设备的函数,如果有幸讲到设备会细讲)当中的一个lv_disp_t类型的结构体变量(源码中为disp_def,我们用disp表示,这里是8.3版本)来获取屏幕的,最终我们会发现是通过dispdisp->act_scr,来获取整个屏幕的。

        我们通过查看lv_disp_t结构体,会发现,整个屏幕的本质依然是一个基础的控件,也就是lv_obj_t的“实例对象”,源码如下:

        作为一个基础对象,那他的创建方法我们已经知道了,lv_obj_create()来进行创建,作为祖先控件他是没有父亲的,是一切的起源,所以直接传个NULL,通过查看源码,我们发现NULL是有特殊意义的,如果父对象为NULL话,他在源码中会通过if走另一套程序,直接将对象加入到显示器的屏幕中,我们可以在lv_obj_class_create_obj(注:该函数在lv_obj_create中)中找到这段代码,源码如下:

        我们通过源码可以看出来,一个显示器上是可以存放多个屏幕的,也就是说,我们可以通过lv_obj_create(NULL)来进行创建大量屏幕,并且每调用一次,都会将其记录在当前显示器当中。

        那我们如何将屏幕显示出来,也就是设置为当前活跃的屏幕呢?使用结构体直接设置是肯定不行的,LVGL毕竟是C写的,没有像前端VUE框架那种实时检测对象数据发生变化的功能,当然我也不太懂前端框架,只是隐约记得VUE好像有类似的功能。

        我们在实际开发中主要是利用LVGL内部提供的两个函数接口来进行加载屏幕,lv_scr_load(obj)与lv_scr_load_anim(obj, LV_SCR_LOAD_ANIM_OVER_LEFT, 0, 0, true),这两个函数接口的区别不大,主要前一个无动画效果,后一个有动画效果,如果我们细究源码,会发现其实只有一个函数接口lv_scr_load_anim,而lv_scr_load不过是将lv_scr_load_anim封装了一下,我实际开发中也是喜欢直用lv_scr_load_anim,源码如下:

        lv_scr_load_anim参数,分别是:要加载的屏幕、动画效果、动画持续多长时间、动画延迟多长时间执行、以及是否删除前一个屏幕。

        主要解释一下动画有关的参数,第二个参数就是屏幕加载时的动画方式,第三个与第四个单位是毫秒,第二个参数,官网给的如下:

1.LV_SCR_LOAD_ANIM_NONE: 在 delay 毫秒后立即切换

2.LV_SCR_LOAD_ANIM_OVER_LEFTLV_SCR_LOAD_ANIM_OVER_RIGHTLV_SCR_LOAD_ANIM_OVER_TOP 和 LV_SCR_LOAD_ANIM_OVER_BOTTOM:将新屏幕沿着给定方向移动到当前屏幕上方

3.LV_SCR_LOAD_ANIM_OUT_LEFTLV_SCR_LOAD_ANIM_OUT_RIGHTLV_SCR_LOAD_ANIM_OUT_TOP 和 LV_SCR_LOAD_ANIM_OUT_BOTTOM:将旧屏幕沿着给定方向移出到当前屏幕外

4.LV_SCR_LOAD_ANIM_MOVE_LEFTLV_SCR_LOAD_ANIM_MOVE_RIGHTLV_SCR_LOAD_ANIM_MOVE_TOP 和LV_SCR_LOAD_ANIM_MOVE_BOTTOM:将当前屏幕和新屏幕都沿着给定方向移动

5.LV_SCR_LOAD_ANIM_FADE_IN 和 LV_SCR_LOAD_ANIM_FADE_OUT:将新屏幕渐变到旧屏幕上,或反之亦然

        具体动画原理,在讲动画时候细讲,这里只是提一嘴。言归正传,我们查看lv_scr_load_anim,会发现他是通过lv_obj_get_disp获取我们在lv_obj_create(NULL)时Obj被添加进的lv_disp_t类型的结构体(注:也就是默认显示器)。

        然后删除掉obj的部分样式,再通过时间判断是否有动画,如果没有,则直接进行加载屏幕,再判断是否删除前一个屏幕,我们查看源码会发现,删除屏幕,其实就是lv_obj_del,删除普通对象的操作,部分源码如下:

        这段源码,我们重点在于scr_load_internal函数,我们查看这个函数会让我们能更好的理解一个概念“生命周期”,在了解生命周期之前,我们先查看一下该函数,源码如下:

        我们查看该函数就会发现,函数很简单,依然是获取默认显示器,然后将屏幕赋值给lv_disp_t中的act_scr,然后通过这个函数lv_obj_invalidate来标记屏幕是要绘制到显示器上的,当lvgl执行任务函数的时候就会根据lv_obj_t的属性来绘制这个屏幕了。

        这时候我们就发现好像混进来多余的东西lv_event_send,这个lv_event_send是用来干嘛的?这个函数的主要功能是向指定控件发送事件的,lv_event_send在这里作用就是,在屏幕删除时和在屏幕创建时向控件发送特殊的事件,这种事件有一种特殊的概念。叫做“生命周期”,

        所谓的“生命周期”,其实就是我们人的一生,出生、长大、衰老、死亡,只不过人换成了屏幕而已,那这些事件有啥用呢?

        那可有大用了,就跟我们刚出生时一样,我们第一次哭,就是告诉世界,我来了!当父母跟医生听到我们哭声,就可以给我们检查身体,喂食之类的操作了。当我们不行去世了,那么遗嘱可以告诉子女们可以分遗产、如何分。

        那屏幕也是如此,如果屏幕加载好了,我们则可以通过事件加载一下动画啊,立刻更新数据之类的,当屏幕删除时,我们也可以通过事件保存一下数据,清理一下还在执行的动画,避免人死了钱还在。

        当然这里只有一个概念就好了,等讲到事件时候会细讲这一块。

        这样屏幕的加载过程,我们大概就能理解了,但还有个小细节,屏幕是不能设置位置的。并且,屏幕还有两个伴生的控件,两个是自动生成的,并不需要我们手动创建。lv_layer_top() 和 lv_layer_sys(),称之为顶层与系统层,在官网是按照层级分的,顶层在屏幕的上面,系统层在顶层的上面,顶层设计出来的目的主要是用来放弹窗的,避免被其他控件遮住,而系统层是用来放鼠标光标之类的,确保鼠标之类的在最顶层,能让用户实时看得见。

        我们主要操作顶层,比如用户要删除一些文件之类的,就可以在顶层创建一个弹窗,询问用户是否要进行删除,避免误触之类的。比如需要加载一个过场动画,这时候可以在顶层创建一个透明的控件作为遮罩,避免用户乱点,从而出现bug。

        而这两个层其实也就是两个lv_obj_t的控件,源码如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值