mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-14 06:42:58 +08:00
282 lines
9.6 KiB
ReStructuredText
282 lines
9.6 KiB
ReStructuredText
|
======
|
||
|
Scroll
|
||
|
======
|
||
|
|
||
|
Overview
|
||
|
********
|
||
|
|
||
|
In LVGL scrolling works very intuitively: if an object is outside its
|
||
|
parent content area (the size without padding), the parent becomes
|
||
|
scrollable and scrollbar(s) will appear. That's it.
|
||
|
|
||
|
Any object can be scrollable including ``lv_obj_t``, ``lv_img``,
|
||
|
``lv_btn``, ``lv_meter``, etc
|
||
|
|
||
|
The object can either be scrolled horizontally or vertically in one
|
||
|
stroke; diagonal scrolling is not possible.
|
||
|
|
||
|
Scrollbar
|
||
|
---------
|
||
|
|
||
|
Mode
|
||
|
^^^^
|
||
|
|
||
|
Scrollbars are displayed according to a configured ``mode``. The
|
||
|
following ``mode``\ (s) exist:
|
||
|
|
||
|
- :cpp:enumerator:`LV_SCROLLBAR_MODE_OFF`: Never show the scrollbars
|
||
|
- :cpp:enumerator:`LV_SCROLLBAR_MODE_ON`: Always show the scrollbars
|
||
|
- :cpp:enumerator:`LV_SCROLLBAR_MODE_ACTIVE`: Show scroll bars while an object is being scrolled
|
||
|
- :cpp:enumerator:`LV_SCROLLBAR_MODE_AUTO`: Show scroll bars when the content is large enough to be scrolled
|
||
|
|
||
|
``lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_...)`` sets the scrollbar mode on an object.
|
||
|
|
||
|
Styling
|
||
|
^^^^^^^
|
||
|
|
||
|
The scrollbars have their own dedicated part, called
|
||
|
:cpp:enumerator:`LV_PART_SCROLLBAR`. For example a scrollbar can turn to red like
|
||
|
this:
|
||
|
|
||
|
.. code:: c
|
||
|
|
||
|
static lv_style_t style_red;
|
||
|
lv_style_init(&style_red);
|
||
|
lv_style_set_bg_color(&style_red, lv_color_red());
|
||
|
|
||
|
...
|
||
|
|
||
|
lv_obj_add_style(obj, &style_red, LV_PART_SCROLLBAR);
|
||
|
|
||
|
An object goes to the :cpp:enumerator:`LV_STATE_SCROLLED` state while it's being
|
||
|
scrolled. This allows adding different styles to the scrollbar or the
|
||
|
object itself when scrolled. This code makes the scrollbar blue when the
|
||
|
object is scrolled:
|
||
|
|
||
|
.. code:: c
|
||
|
|
||
|
static lv_style_t style_blue;
|
||
|
lv_style_init(&style_blue);
|
||
|
lv_style_set_bg_color(&style_blue, lv_color_blue());
|
||
|
|
||
|
...
|
||
|
|
||
|
lv_obj_add_style(obj, &style_blue, LV_STATE_SCROLLED | LV_PART_SCROLLBAR);
|
||
|
|
||
|
If the base direction of the :cpp:enumerator:`LV_PART_SCROLLBAR` is RTL
|
||
|
(:c:macro:`LV_BASE_DIR_RTL`) the vertical scrollbar will be placed on the left.
|
||
|
Note that, the ``base_dir`` style property is inherited. Therefore, it
|
||
|
can be set directly on the :cpp:enumerator:`LV_PART_SCROLLBAR` part of an object or on
|
||
|
the object's or any parent's main part to make a scrollbar inherit the
|
||
|
base direction.
|
||
|
|
||
|
``pad_left/right/top/bottom`` sets the spacing around the scrollbars and
|
||
|
``width`` sets the scrollbar's width.
|
||
|
|
||
|
Events
|
||
|
------
|
||
|
|
||
|
The following events are related to scrolling:
|
||
|
|
||
|
- :cpp:enumerator:`LV_EVENT_SCROLL_BEGIN`: Scrolling begins. The event parameter is
|
||
|
``NULL`` or an ``lv_anim_t *`` with a scroll animation descriptor that can be modified if required.
|
||
|
- :cpp:enumerator:`LV_EVENT_SCROLL_END`: Scrolling ends.
|
||
|
- :cpp:enumerator:`LV_EVENT_SCROLL`: Scroll happened. Triggered on every position change. Scroll events
|
||
|
|
||
|
Basic example
|
||
|
*************
|
||
|
|
||
|
TODO
|
||
|
|
||
|
Features of scrolling
|
||
|
*********************
|
||
|
|
||
|
Besides, managing "normal" scrolling there are many interesting and
|
||
|
useful additional features.
|
||
|
|
||
|
Scrollable
|
||
|
----------
|
||
|
|
||
|
It's possible to make an object non-scrollable with
|
||
|
:cpp:expr:`lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE)`.
|
||
|
|
||
|
Non-scrollable objects can still propagate the scrolling (chain) to
|
||
|
their parents.
|
||
|
|
||
|
The direction in which scrolling happens can be controlled by
|
||
|
``lv_obj_set_scroll_dir(obj, LV_DIR_...)``. The following values are
|
||
|
possible for the direction:
|
||
|
- :cpp:enumerator:`LV_DIR_TOP`: only scroll up
|
||
|
- :cpp:enumerator:`LV_DIR_LEFT`: only scroll left
|
||
|
- :cpp:enumerator:`LV_DIR_BOTTOM`: only scroll down
|
||
|
- :cpp:enumerator:`LV_DIR_RIGHT`: only scroll right
|
||
|
- :cpp:enumerator:`LV_DIR_HOR`: only scroll horizontally
|
||
|
- :cpp:enumerator:`LV_DIR_VER`: only scroll vertically
|
||
|
- :cpp:enumerator:`LV_DIR_ALL`: scroll any directions
|
||
|
|
||
|
OR-ed values are also possible. E.g. :cpp:expr:`LV_DIR_TOP | LV_DIR_LEFT`.
|
||
|
|
||
|
Scroll chain
|
||
|
------------
|
||
|
|
||
|
If an object can't be scrolled further (e.g. its content has reached the
|
||
|
bottom-most position) additional scrolling is propagated to its parent.
|
||
|
If the parent can be scrolled in that direction than it will be scrolled
|
||
|
instead. It continues propagating to the grandparent and
|
||
|
grand-grandparents as well.
|
||
|
|
||
|
The propagation on scrolling is called "scroll chaining" and it can be
|
||
|
enabled/disabled with ``LV_OBJ_FLAG_SCROLL_CHAIN_HOR/VER`` flag. If
|
||
|
chaining is disabled the propagation stops on the object and the
|
||
|
parent(s) won't be scrolled.
|
||
|
|
||
|
Scroll momentum
|
||
|
---------------
|
||
|
|
||
|
When the user scrolls an object and releases it, LVGL can emulate
|
||
|
inertial momentum for the scrolling. It's like the object was thrown and
|
||
|
scrolling slows down smoothly.
|
||
|
|
||
|
The scroll momentum can be enabled/disabled with the
|
||
|
:cpp:enumerator:`LV_OBJ_FLAG_SCROLL_MOMENTUM` flag.
|
||
|
|
||
|
Elastic scroll
|
||
|
--------------
|
||
|
|
||
|
Normally an object can't be scrolled past the extremeties of its
|
||
|
content. That is the top side of the content can't be below the top side
|
||
|
of the object.
|
||
|
|
||
|
However, with :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_ELASTIC` a fancy effect is added
|
||
|
when the user "over-scrolls" the content. The scrolling slows down, and
|
||
|
the content can be scrolled inside the object. When the object is
|
||
|
released the content scrolled in it will be animated back to the valid
|
||
|
position.
|
||
|
|
||
|
Snapping
|
||
|
--------
|
||
|
|
||
|
The children of an object can be snapped according to specific rules
|
||
|
when scrolling ends. Children can be made snappable individually with
|
||
|
the :cpp:enumerator:`LV_OBJ_FLAG_SNAPPABLE` flag.
|
||
|
|
||
|
An object can align snapped children in four ways:
|
||
|
|
||
|
- :cpp:enumerator:`LV_SCROLL_SNAP_NONE`: Snapping is disabled. (default)
|
||
|
- :cpp:enumerator:`LV_SCROLL_SNAP_START`: Align the children to the left/top side of a scrolled object
|
||
|
- :cpp:enumerator:`LV_SCROLL_SNAP_END`: Align the children to the right/bottom side of a scrolled object
|
||
|
- :cpp:enumerator:`LV_SCROLL_SNAP_CENTER`: Align the children to the center of a scrolled object
|
||
|
|
||
|
Snap alignment is set with
|
||
|
``lv_obj_set_scroll_snap_x/y(obj, LV_SCROLL_SNAP_...)``:
|
||
|
|
||
|
Under the hood the following happens:
|
||
|
|
||
|
1. User scrolls an object and releases the screen
|
||
|
2. LVGL calculates where the scroll would end considering scroll momentum
|
||
|
3. LVGL finds the nearest scroll point
|
||
|
4. LVGL scrolls to the snap point with an animation
|
||
|
|
||
|
Scroll one
|
||
|
----------
|
||
|
|
||
|
The "scroll one" feature tells LVGL to allow scrolling only one
|
||
|
snappable child at a time. This requires making the children snappable
|
||
|
and setting a scroll snap alignment different from
|
||
|
:cpp:enumerator:`LV_SCROLL_SNAP_NONE`.
|
||
|
|
||
|
This feature can be enabled by the :cpp:enumerator:`LV_OBJ_FLAG_SCROLL_ONE` flag.
|
||
|
|
||
|
Scroll on focus
|
||
|
---------------
|
||
|
|
||
|
Imagine that there a lot of objects in a group that are on a scrollable
|
||
|
object. Pressing the "Tab" button focuses the next object but it might
|
||
|
be outside the visible area of the scrollable object. If the "scroll on
|
||
|
focus" feature is enabled LVGL will automatically scroll objects to
|
||
|
bring their children into view. The scrolling happens recursively
|
||
|
therefore even nested scrollable objects are handled properly. The
|
||
|
object will be scrolled into view even if it's on a different page of a
|
||
|
tabview.
|
||
|
|
||
|
Scroll manually
|
||
|
***************
|
||
|
|
||
|
The following API functions allow manual scrolling of objects:
|
||
|
|
||
|
- ``lv_obj_scroll_by(obj, x, y, LV_ANIM_ON/OFF)`` scroll by ``x`` and ``y`` values
|
||
|
- ``lv_obj_scroll_to(obj, x, y, LV_ANIM_ON/OFF)`` scroll to bring the given coordinate to the top left corner
|
||
|
- ``lv_obj_scroll_to_x(obj, x, LV_ANIM_ON/OFF)`` scroll to bring the given coordinate to the left side
|
||
|
- ``lv_obj_scroll_to_y(obj, y, LV_ANIM_ON/OFF)`` scroll to bring the given coordinate to the top side
|
||
|
|
||
|
From time to time you may need to retrieve the scroll position of an
|
||
|
element, either to restore it later, or to display dynamically some
|
||
|
elements according to the current scroll. Here is an example to see how
|
||
|
to combine scroll event and store the scroll top position.
|
||
|
|
||
|
.. code:: c
|
||
|
|
||
|
static int scroll_value = 0;
|
||
|
|
||
|
static void store_scroll_value_event_cb(lv_event_t* e) {
|
||
|
lv_obj_t* screen = lv_event_get_target(e);
|
||
|
scroll_value = lv_obj_get_scroll_top(screen);
|
||
|
printf("%d pixels are scrolled out on the top\n", scroll_value);
|
||
|
}
|
||
|
|
||
|
lv_obj_t* container = lv_obj_create(NULL);
|
||
|
lv_obj_add_event(container, store_scroll_value_event_cb, LV_EVENT_SCROLL, NULL);
|
||
|
|
||
|
Scrool coordinates can be retrieve from differents axes with these
|
||
|
functions:
|
||
|
|
||
|
- ``lv_obj_get_scroll_x(obj)`` Get the ``x`` coordinate of object
|
||
|
- ``lv_obj_get_scroll_y(obj)`` Get the ``y`` coordinate of object
|
||
|
- ``lv_obj_get_scroll_top(obj)`` Get the scroll coordinate from the top
|
||
|
- ``lv_obj_get_scroll_bottom(obj)`` Get the scroll coordinate from the bottom
|
||
|
- ``lv_obj_get_scroll_left(obj)`` Get the scroll coordinate from the left
|
||
|
- ``lv_obj_get_scroll_right(obj)`` Get the scroll coordinate from the right
|
||
|
|
||
|
|
||
|
Self size
|
||
|
*********
|
||
|
|
||
|
Self size is a property of an object. Normally, the user shouldn't use
|
||
|
this parameter but if a custom widget is created it might be useful.
|
||
|
|
||
|
In short, self size establishes the size of an object's content. To
|
||
|
understand it better take the example of a table. Let's say it has 10
|
||
|
rows each with 50 px height. So the total height of the content is 500
|
||
|
px. In other words the "self height" is 500 px. If the user sets only
|
||
|
200 px height for the table LVGL will see that the self size is larger
|
||
|
and make the table scrollable.
|
||
|
|
||
|
This means not only the children can make an object scrollable but a
|
||
|
larger self size will too.
|
||
|
|
||
|
LVGL uses the :cpp:enumerator:`LV_EVENT_GET_SELF_SIZE` event to get the self size of
|
||
|
an object. Here is an example to see how to handle the event:
|
||
|
|
||
|
.. code:: c
|
||
|
|
||
|
if(event_code == LV_EVENT_GET_SELF_SIZE) {
|
||
|
lv_point_t * p = lv_event_get_param(e);
|
||
|
|
||
|
//If x or y < 0 then it doesn't neesd to be calculated now
|
||
|
if(p->x >= 0) {
|
||
|
p->x = 200; //Set or calculate the self width
|
||
|
}
|
||
|
|
||
|
if(p->y >= 0) {
|
||
|
p->y = 50; //Set or calculate the self height
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Examples
|
||
|
********
|
||
|
|
||
|
.. include:: ../examples/scroll/index.rst
|
||
|
|
||
|
API
|
||
|
***
|