LVGL Pro 使用指南 [15] LVGL XML 控件
概述 链接到标题
控件 (Widgets) 是 LVGL 的主要构建块之一,与组件(Components)和屏幕(Screens)并列。控件的 XML 文件以<widget>作为根元素,支持以下子标签:
<consts>:定义常量<api>:定义 API 接口<styles>:定义样式<view>:定义视图<previews>:定义预览
控件可以嵌套在其他控件或组件中。控件不能直接从 XML 加载,但可以通过编写和注册简单的 XML 解析器来实现。
对于一般的界面开发用户,实现控件的场景并不多。同时绝大多数情况都只会使用<api>标签描述控件的接口,让 LVGL XML 可以通过接口使用控件的功能,而控件的解释器需要通过 C 语言来实现,这超出了本文的说明范围。基于以上因素,说明控件的 XML 的必要性并不大,这也是本系列文章接近尾声时才开始介绍控件的原因。
内置控件 链接到标题
LVGL 提供了许多内置的控件,例如:lv_slider、lv_label、lv_chart 等。在 LVGL 的仓库内有专门的 XML 文件来描述这些控件的接口: https://github.com/lvgl/lvgl/tree/master/xmls
这些 XML 文件会描述控件的接口,并注释如何使用,例如其中的lv_slider.xml文件:
<!--
Example
<lv_spinner anim_duration="1500" arc_sweep="90"/>
-->
<widget>
<api>
<prop name="anim_duration" type="int" help="Set the animation time of the spinner."/>
<prop name="arc_sweep" type="int" help="Set the animation arc length of the spinner. The animation is suited to values between 180 and 360."/>
</api>
</widget>
控件的解析器代码放在:https://github.com/lvgl/lvgl/tree/master/src/xml
API 链接到标题
控件通过<api>标签描述其接口,该标签下主要通过<prop>(属性)子标签描述接口。
属性 链接到标题
属性是描述控件接口的核心部分,例如下面的示例表示该控件有一个 text 属性可以设置,类型是字符串:
<api>
<prop name="text" type="string" help="Text of the label."/>
</api>
参数 链接到标题
属性可以由多个参数构成,例如:
<api>
<prop name="bind_text" help="Bind a subject's value to a label.">
<param name="bind_text" type="subject" help="Integer or string subject"/>
<param name="fmt" type="string" help="Format string, e.g. %d °C "/>
</prop>
</api>
名称与属性相同的参数可以直接引用。其他参数则使用"属性-参数(property-param)“的方式引用。未设置的参数的情况:
- 使用默认值(如果已定义)
- 类型特定的默认值(例如 0、false、NULL)
在解析器中,每个<prop>都映射到一个设置函数。同一属性下的<param>会被传递给同一个设置函数。
<enumdef>
链接到标题
<enumdef>仅用于控件,此标签用于为参数值定义枚举。例如:
<api>
<enumdef name="my_widget_mode" help="Possible modes">
<enum name="normal" help="Normal mode" value="0x10"/>
<enum name="inverted" help="Inverted mode"/>
</enumdef>
<prop name="mode" help="Set Widget mode">
<param name="mode" type="enum:my_widget_mode"/>
</prop>
</api>
<element>
链接到标题
<element>仅用于控件,此标签用于定义子控件(sub-widgets)或内部结构(例如:图表序列、下拉列表、标签视图)。也常用于创建类似"插槽(slots)“的结构(类似 tabview 的 tab),例如窗口部件中的内容区和标题区,允许直接在其中创建子对象。
<element>包含<arg>和<prop>子标签:
<arg>是必需的,用于创建或获取 element 时传入<prop>是可选的,映射到 setter 函数
下面是一个示例,用于定义一个可以动态添加到控件的"indicator”。它会创建my_indicator_t *类型的元素,类似于lv_chart_add_series的方式:
<api>
<element name="indicator" type="my_indicator_t" help="The indicator of my_widget" access="add">
<!-- args are passed when the element is created -->
<arg name="color" type="color"/>
<arg name="max_value" type="int"/>
<!-- props can be set by setters at any time -->
<prop name="value" type="int"/>
</element>
</api>
Element 的 access 类型:
- add:动态创建多个元素,例如 tabview 的 tabs
- get:访问隐式创建的元素,例如 dropdown 的列表部分
- set:访问按索引存在的部分,例如 table 的 cells
- custom:映射自定义 C 函数到 XML,例如 bind_state_is_eq
add 与 get 类型的 element 都会返回一个对象,因此需要声明type。该type可以是任何自定义类型,例如type="my_data"。在导出的 C 代码中,返回值会保存在my_data_t *类型的变量中。如果type="lv_obj",该 element 允许拥有子控件或组件。
Element 在<view>中以<widget-element>的形式引用。名称部分使用-分隔。
注意:Element 只能在 XML 中定义其 API;实现必须写在 C 代码中。
access="add"
链接到标题
通过 add 创建的名为indicator的 Element:
<api>
<element name="indicator" type="obj" help="The indicator of my_widget" access="add">
<arg name="color" type="color"/>
<arg name="max_value" type="int"/>
<prop name="value">
<param name="value" type="int"/>
</prop>
</element>
</api>
使用方法如下:
<my_widget width="100px">
<my_widget-indicator name="indic1" color="0xff0000" max_value="120" value="30"/>
</my_widget>
通过 LVGL Pro Editor 会生成以下 add 原型,需要另外写 C 代码实现:
lv_obj_t * my_widget_add_indicator(lv_obj_t * parent, lv_color_t color, int32_t max_value);
void my_widget_set_indicator_value(lv_obj_t * obj, int32_t value);
access="get"
链接到标题
通过 get 创建的名为control_button的 Element:
<api>
<element name="control_button" type="obj" help="A control button of my_widget" access="get">
<arg name="index" type="int"/>
<prop name="title" type="string"/>
</element>
</api>
使用方法如下:
<my_widget width="100px">
<my_widget-control_button name="btn1" index="3" title="Hello"/>
</my_widget>
通过 LVGL Pro Editor 会生成以下 get 原型,需要另外写 C 代码实现:
lv_obj_t * my_widget_get_control_button(lv_obj_t * parent, int32_t index);
void my_widget_set_control_button_title(lv_obj_t * obj, const char * text);
access="set"
链接到标题
通过 set 创建的名为item的 Element:
<api>
<element name="item" type="obj" access="set">
<arg name="index" type="int"/>
<prop name="icon" type="img_src"/>
<prop name="color" type="color"/>
</element>
</api>
使用方法如下:
<my_widget width="100px">
<my_widget-item index="3" icon_src="image1" color="0xff0000"/>
</my_widget>
通过 LVGL Pro Editor 会生成以下 set 原型,需要另外写 C 代码实现:
void my_widget_set_item_icon(lv_obj_t * parent, int32_t index, const void * icon_src);
void my_widget_set_item_color(lv_obj_t * parent, int32_t index, lv_color_t color);
access="custom"
链接到标题
通过 custom 创建的名为bind_color的 Element:
<element name="bind_color" access="custom">
<arg name="subject" type="subject"/>
<arg name="new_color" type="color"/>
<arg name="ref_value" type="int"/>
</element>
使用方法如下:
<my_widget width="100px">
<my_widget-bind_color subject="subject_1" color="0xff0000" ref_value="15"/>
</my_widget>
通过 LVGL Pro Editor 会生成以下自定义原型,需要另外写 C 代码实现:
void my_widget_bind_color(lv_obj_t * parent, lv_subject_t * subject, lv_color_t color, int32_t ref_value);
参考 链接到标题
https://docs.lvgl.io/master/xml/ui_elements/widgets.html https://docs.lvgl.io/master/xml/ui_elements/api.html