Components

Overview

<component> can have <consts>, <api>, <styles>, and <view> tags inside.

Unlike widgets (which are always compiled into the application), components can either:

  1. Be loaded at runtime from XML.

  2. Be exported to C code.

Usage from Exported Code

From each component XML file, a C and H file is exported with a single function inside:

lv_obj_t * component_name_create(lv_obj_t * parent, ...api properties...);

When a component is used in another component’s XML code and the code is exported, this create function will be called. This means that components do not have a detailed set/get API but can be created with a fixed set of parameters.

If the user needs to access or modify values dynamically, it is recommended to use a subject.

The user can also call these _create_ functions at any time from the application code.

Usage from XML

Registration

Once a component is created (e.g., my_button), it can be registered by calling either:

  • lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_button.xml");

  • lv_xml_component_register_from_data("my_button", xml_data_of_my_button);

These registration functions process the XML data and store relevant information internally. This is required to make LVGL recognize the component by name.

When loaded from a file, the file name is used as the component name.

Instantiation

After registration, a new instance of any registered component can be created with:

lv_obj_t * obj = lv_xml_create(lv_screen_active(), "my_button", NULL);

The created widget is a normal LVGL widget that can be used like any other manually created widget.

The last parameter can be NULL or an attribute list, like this:

/* Can be local */
char * my_button_attrs[] = {
    "x", "10",
    "y", "-10",
    "align", "bottom_left",
    "btn_text", "New button",
    NULL, NULL,
};

lv_obj_t * btn1 = lv_xml_create(lv_screen_active(), "my_button", my_button_attrs);

Parameters

The properties of child elements can be adjusted, such as:

<lv_label x="10" text="Hello"/>

These parameters can be set to a fixed value. However, with the help of <prop> elements inside the <api> tag, they can also be passed when an instance is created. Only the whole property can be passed, but not individual <param> elements.

Additionally, when a component is created, it can use the extended widget's attributes (see <view extends="...">).

This means that components inherit the API of the extended widget as well.

The following example demonstrates parameter passing and the use of the text label property on a component:

<!-- h3.xml -->
<component>
    <view extends="lv_label"/>
</component>
<!-- red_button.xml -->
<component>
    <api>
        <prop type="string" name="btn_text" default="None"/>
    </api>
    <view extends="lv_button" style_radius="0" style_bg_color="0xff0000">
        <h3 text="Some text"/>
        <h3 text="$btn_text" y="40"/>
    </view>
</component>
lv_xml_component_register_from_file("A:path/to/h3.xml");
lv_xml_component_register_from_file("A:path/to/red_button.xml");

/* Creates a button with "None" text */
lv_xml_create(lv_screen_active(), "red_button", NULL);

/* Use attributes to set the button text */
const char * attrs[] = {
    "btn_text", "Click here",
    NULL, NULL,
};
lv_xml_create(lv_screen_active(), "red_button", attrs);

Example

Load components at runtime

#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_XML

void lv_example_xml_1(void)
{
    /*A red button created from builti-in LVGL widgets
     *It has an API parameter too to change its text.*/
    const char * red_button_xml =
        "<component>"
        "  <api>"
        "    <prop name=\"button_text\" type=\"string\" default=\"None\"/>"
        "  </api>"
        "  <view extends=\"lv_button\" radius=\"0\" style_bg_color=\"0xa91500\">"
        "    <lv_label text=\"$button_text\" align=\"center\"/>"
        "  </view>"
        "</component>";

    /*The card is just an lv_obj where a label and two red buttons are used.
     * Its API allow setting a title (label test) and the action (the text of a button)*/
    const char * card_xml =
        "<component>"
        "  <api>"
        "    <prop name=\"title\" type=\"string\" default=\"Hello world\"/>"
        "    <prop name=\"action\" type=\"string\"/>"
        "  </api>"
        "  <view width=\"200\" height=\"content\">"
        "    <lv_label text=\"$title\" align=\"top_mid\"/>"
        "    <red_button y=\"20\" align=\"top_left\" button_text=\"Cancel\"/>"
        "    <red_button y=\"20\" align=\"top_right\" button_text=\"$action\"/>"
        "  </view>"
        "</component>";

    /* Motor card is a special case of a card where the title and action are already set*/
    const char * motor_card_xml =
        "<component>"
        "  <view extends=\"card\" title=\"Motor start?\" action=\"Start\">"
        "  </view>"
        "</component>";

    /*Register all the custom components*/
    lv_xml_component_register_from_data("red_button", red_button_xml);
    lv_xml_component_register_from_data("card", card_xml);
    lv_xml_component_register_from_data("motor_card", motor_card_xml);

    lv_obj_t * card;
    /*Create a card with the default values*/
    card = lv_xml_create(lv_screen_active(), "card", NULL);

    /*Create a motor card too. The returned value can be adjusted freely*/
    card = lv_xml_create(lv_screen_active(), "motor_card", NULL);
    lv_obj_set_y(card, 90);

    /*Pass properties to a card*/
    const char * attrs[] = {
        "y", "180",
        "action", "Apply",
        "title", "New title",
        NULL, NULL,
    };
    card = lv_xml_create(lv_screen_active(), "card", attrs);

}
#endif

#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_XML

void lv_example_xml_2(void)
{
    lv_result_t res;
    res = lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_h3.xml");
    if(res != LV_RESULT_OK) {
        lv_obj_t * label = lv_label_create(lv_screen_active());
        lv_label_set_text(label, "Couldn't open the XML files.");
        lv_obj_center(label);
        return;
    }
    lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_card.xml");
    lv_xml_component_register_from_file("A:lvgl/examples/others/xml/my_button.xml");
    lv_xml_component_register_from_file("A:lvgl/examples/others/xml/view.xml");

    lv_xml_register_font("lv_montserrat_18", &lv_font_montserrat_18);

    lv_obj_t * obj = lv_xml_create(lv_screen_active(), "view", NULL);
    lv_obj_set_pos(obj, 10, 10);

    const char * my_button_attrs[] = {
        "x", "10",
        "y", "-10",
        "align", "bottom_left",
        "btn_text", "New button",
        NULL, NULL,
    };

    lv_xml_component_unregister("my_button");

    lv_xml_create(lv_screen_active(), "my_button", my_button_attrs);

    const char * slider_attrs[] = {
        "x", "200",
        "y", "-15",
        "align", "bottom_left",
        "value", "30",
        NULL, NULL,
    };

    lv_obj_t * slider = lv_xml_create(lv_screen_active(), "lv_slider", slider_attrs);
    lv_obj_set_width(slider, 100);
}
#endif

API