Data Binding
Learn how to use subjects for data binding to create dynamic, responsive UIs that update automatically.
Overview
With the help of subjects, the interface of the UI can be created.
A subject is a global data item whose value can be set either from the application or the UI, and whose value can be bound to widget properties.
Designing in Figma? You can bind layers to subjects directly in the plugin, no code required. See Subjects & Data Binding in Figma Flow.
For example, a room1_temperature subject's value can be set in the
application when the temperature is measured, and can be bound to a
label like this:
<lv_label bind_text="room1_temperature"/>Defining subjects
Subjects can be created in globals.xml like this:
<globals>
<subjects>
<int name="battery_power" value="32"/>
<string name="user_name" value="John"/>
<float name="room_temperature" value="21.5"/>
</subjects>
</globals>As the example shows, a subject consists of a type, name, and initial value. Integer, string, and float types are supported.
Float subjects require LV_USE_FLOAT to be enabled in lv_conf.h. Without it, the generated code fails to compile.
Simple binding
Some widgets (e.g., label, slider) support binding the subject's value
directly to the widget. These bindings use attributes that start with
bind_* and reference a subject.
<lv_slider bind_value="some_subject"/>
<lv_label bind_text="some_subject"/>Once a binding is created, if the subject's value changes (e.g., by adjusting the slider), all bound widgets will be updated automatically.
Complex binding
In more complex cases---when a binding requires multiple parameters---the binding can be added as a child element of a widget. This allows binding multiple subjects with different parameters. For example:
<lv_label text="Hello world">
<lv_obj-bind_flag_if_eq subject="subject1" flag="hidden" ref_value="10"/>
<lv_obj-bind_flag_if_gt subject="subject1" flag="clickable" ref_value="20"/>
</lv_label>Explanation of complex bindings:
| Binding Type | Condition | Description |
|---|---|---|
bind_flag_if_eq | Equals | Set a flag if the subject's value equals the reference value |
bind_flag_if_not_eq | Not equals | Set a flag if the subject's value does not equal the reference value |
bind_flag_if_gt | Greater than | Set a flag if the subject's value is greater than the reference value |
bind_flag_if_ge | Greater or equal | Set a flag if the subject's value is greater than or equal to the reference value |
bind_flag_if_lt | Less than | Set a flag if the subject's value is less than the reference value |
bind_flag_if_le | Less or equal | Set a flag if the subject's value is less than or equal to the reference value |
bind_state_if_eq | Equals | Set a state if the subject's value equals the reference value |
bind_state_if_not_eq | Not equals | Set a state if the subject's value does not equal the reference value |
bind_state_if_gt | Greater than | Set a state if the subject's value is greater than the reference value |
bind_state_if_ge | Greater or equal | Set a state if the subject's value is greater than or equal to the reference value |
bind_state_if_lt | Less than | Set a state if the subject's value is less than the reference value |
bind_state_if_le | Less or equal | Set a state if the subject's value is less than or equal to the reference value |
Note: The lv_obj- prefix can be omitted. For example, you can simply
write bind_state_if_gt instead.
Choosing the right attribute
bind_flag_* and bind_state_* look almost identical but expect a different attribute and a different set of values:
bind_flag_*toggles a widget flag — use theflagattribute.bind_state_*toggles a widget state — use thestateattribute.
<!-- Set the "hidden" flag while subject_mode != 1 -->
<lv_obj>
<bind_flag_if_not_eq subject="subject_mode" flag="hidden" ref_value="1"/>
</lv_obj>
<!-- Enter the "checked" state while subject_lamp == 2 -->
<lv_obj>
<bind_state_if_eq subject="subject_lamp" state="checked" ref_value="2"/>
</lv_obj>Valid state values
These match LVGL's LV_STATE_* constants. The same names are used as style selectors and in bind_state_* bindings.
| Value | Meaning |
|---|---|
default | Widget is in its base state |
checked | Widget is toggled on (e.g. a checkable button) |
focused | Widget has focus from any input device |
focus_key | Widget has focus from a keypad/encoder |
edited | Widget is being edited (e.g. encoder edit mode) |
hovered | Pointer is over the widget |
pressed | Widget is currently pressed |
scrolled | Widget is being scrolled |
disabled | Widget rejects input |
Valid flag values
The most commonly bound LV_OBJ_FLAG_* flags, exposed by the same names without the prefix:
| Value | Effect when set |
|---|---|
hidden | Widget is not drawn and ignores input |
clickable | Widget can be pressed/clicked |
checkable | Click toggles the checked state |
scrollable | Widget can be scrolled |
scroll_on_focus | Parent scrolls so the focused child is visible |
floating | Excluded from the parent's layout |
ignore_layout | Ignored by the parent's layout |
For the full list of states and flags see LVGL's Object basics and Style states reference.
Selection groups via a shared subject
A common pattern is to express "exactly one of these widgets is active" with a single integer subject and one ref_value per option. Combining subject_set_int_event (writes the subject on click) with bind_state_if_eq (reads it to drive the checked state) produces a runtime-driven radio group with no application code.
<!-- globals.xml -->
<subjects>
<int name="subject_lamp" value="0"/>
</subjects><!-- lamp_cell.xml — one cell instantiated per option -->
<component>
<api>
<prop name="label" type="string" default="Lamp"/>
<prop name="ref_value" type="int" default="0"/>
</api>
<view extends="lv_obj" width="content" height="content" flex_flow="column">
<lv_label text="$label"/>
<lv_button style_bg_color-checked="0xed7d31">
<lv_image src="img_lightbulb"/>
<!-- Read: this button is checked iff subject_lamp == ref_value -->
<bind_state_if_eq subject="subject_lamp" state="checked" ref_value="$ref_value"/>
<!-- Write: clicking this button stores ref_value in subject_lamp -->
<subject_set_int_event subject="subject_lamp" trigger="clicked" value="$ref_value"/>
</lv_button>
</view>
</component><!-- screen — each cell carries a unique ref_value -->
<lamp_cell label="Lamp 1" ref_value="0"/>
<lamp_cell label="Lamp 2" ref_value="1"/>
<lamp_cell label="Lamp 3" ref_value="2"/>When the user taps a cell, subject_lamp is written to that cell's ref_value; every other cell's bind_state_if_eq re-evaluates and drops out of the checked state automatically. The same subject can also be set from C (lv_subject_set_int(&subject_lamp, …)) to drive the selection from application code.
Subject Related Events
Besides binding properties to subjects, it's also possible to add events that change the value of a subject on pressed, release, etc.
Learn more about these in the events documentation.
Last updated on