Scrolling
Scroll-enabled containers and content.
Any lv_obj_t whose content exceeds its bounds can scroll, with per-axis control and optional snap points that lock motion to child boundaries. Scrollbars are themeable through the LV_PART_SCROLLBAR style part, and event callbacks let you translate, fade, or scale children as they move through the viewport. The examples cover scrollbar mode and styling, RTL placement, the scrollable/chain/snap/scroll-one/floating behaviors, scroll events, programmatic scrolling, and the infinite and circular scroll patterns.
Scroll chaining
A nested scrollable can stop scrolling from propagating to its parent.
The outer panel scrolls, and it contains an inner scrollable box that
also overflows. By default, reaching the inner box's edge would "chain"
the remaining scroll to the outer panel. Setting scroll_chain="false"
on the inner box breaks that link, so scrolling stops at the box and
the outer panel does not move.
Endless circular scrolling
Wrap items from one edge to the other so a strip scrolls without limits.
A row strip and a column strip each hold ten buttons. Their
LV_EVENT_SCROLL callback detects when either edge is reached and uses
lv_obj_move_to_index to move the boundary child across, then
compensates with lv_obj_scroll_to_x/y so the visible content does not
jump — making the finite list feel infinite in both directions.
Reacting to scroll events
Read the live scroll position from an LV_EVENT_SCROLL callback.
A panel overflows with buttons so it can be scrolled. On every
LV_EVENT_SCROLL the handler reads lv_obj_get_scroll_y,
lv_obj_get_scroll_top and lv_obj_get_scroll_bottom and writes them
into a label, so the numbers update continuously as the panel is
dragged — the typical way to drive UI from the scroll position.
Floating button over a list
A floating child stays pinned while the list behind it scrolls.
The panel is a scrollable list of buttons. The round "+" button sets
floating="true": a floating child is ignored by the layout and is not
moved when its parent scrolls, so it stays anchored to the bottom-right
corner while the list slides underneath it.
Infinite (virtualized) scrolling
Create rows on demand and delete far-off ones while a column scrolls.
A column tracks the highest and lowest loaded numbers. The
LV_EVENT_SCROLL callback appends or prepends rows while either edge
is within 200 px of content end, and deletes rows once they are more
than 600 px away, compensating each change with lv_obj_scroll_by so
the view stays steady. This keeps the element count bounded no matter
how far the user scrolls.
Scroll one at a time
Restrict each scroll gesture to a single snappable child.
The panel combines centre snapping with scroll_one="true". Snapping
alone lets a fast fling cross several panels before settling; with
"scroll one" enabled every gesture advances by exactly one panel, no
matter how hard it is thrown. It requires snappable children and a
snap mode other than none.
Scroll basics
A panel becomes scrollable on its own when its children overflow it.
The panel is only 140 px tall but stacks six full-width buttons, so the content is taller than the panel. LVGL makes the panel scrollable and shows a vertical scrollbar automatically — no scroll-specific API is used here, only content that exceeds the bounds.
Toggling scroll behaviour flags
Switch SCROLLABLE, SCROLL_CHAIN, SCROLL_ELASTIC and SCROLL_MOMENTUM on live.
These four flags change how a Widget reacts to scrolling but only show
their effect through interaction, so one example covers them together.
A scrollable list sits above four switches; each switch toggles the
corresponding behaviour on the list with its dedicated setter (e.g.
lv_obj_set_scrollable), so the change can be felt immediately by dragging
the list.
Right-to-left scrolling
An RTL base direction moves the vertical scrollbar to the left side.
style_base_dir="rtl" flips the panel's base direction. The vertical
scrollbar is then drawn on the left edge instead of the right, and the
property is inherited, so setting it once on the panel is enough. The
content itself is ordinary so the placement change is the only visible
difference.
Disabling scrolling
Clearing the SCROLLABLE flag clips overflowing content instead of scrolling it.
Both panels hold the same overflowing column of buttons. The left one
keeps the default behaviour and scrolls. The right one sets
scrollable="false", so the flag is cleared: the extra content is
simply clipped and the panel cannot be scrolled at all.
Scrollbar mode
Compare an always-hidden scrollbar with an always-visible one.
Two identical overflowing panels differ only in scrollbar_mode: the
left one is off (scrollable, but the bar is never drawn), the right
one is on (the bar is always drawn even when idle). The other modes
are auto (bar only while scrollable) and active (bar only while
actively scrolling).
Styling the scrollbar
Restyle the SCROLLBAR part into a thick, rounded, coloured bar.
The scrollbar is the scrollbar part of any scrollable Widget. A named
style attached with selector="scrollbar" overrides its width
(thickness), radius, fill colour/opacity and pad_right (gap from
the edge). scrollbar_mode="on" keeps it visible so the styling is
always seen.
Scroll snapping
Snap children to the centre, and opt one child out of snapping.
The row panel sets scroll_snap_x="center", so when a drag is released
the nearest panel animates to the centre. The third button sets
snappable="false", removing it from the snap candidates: scrolling
glides over it and lands on a neighbouring, snappable panel instead.
Scrolling programmatically
Jump, save and restore the scroll position from code with animation.
The panel scrolls because its content overflows. Four buttons drive it
without any user gesture: "Top" and "Bottom" animate to the extremes
via lv_obj_scroll_to_y with LV_ANIM_ON; "Save" records the current
lv_obj_get_scroll_y; "Restore" animates back to the saved offset.
Translate children while scrolling
Bow a column of buttons along a circle as they scroll past the centre.
A circular, corner-clipped container snaps its children vertically. An
LV_EVENT_SCROLL callback measures each child's offset from the
container centre, projects it onto a circle with lv_sqrt, writes the
result to translate_x, and fades distant items toward
LV_OPA_TRANSP — a parallax effect XML styling cannot express.
Last updated on