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> 是必需的,用于创建或获取 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>
使用方法如下:
```xml
<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