I’ve implemented the core logic of circular scrolling. It’s not a ready-to-use widget just a demonstration. It’d be great if someone would be interested in turning it into a widget.
static int32_t act_page_idx = 0;
static void scroll_end_event(lv_event_t * e)
{
lv_obj_t * cont = lv_event_get_target(e);
/* If scroll end came from the user we don't case
* We want to rearrange the grid when snapping moved scrolled.*/
lv_indev_t * indev = lv_indev_get_act();
if(indev) return;
lv_point_t p;
lv_obj_get_scroll_end(cont, &p);
uint32_t child_cnt = lv_obj_get_child_cnt(cont);
lv_coord_t w = lv_obj_get_content_width(cont);
/*Get the current page, can be -1,0,1 for left center, right*/
lv_coord_t page = (p.x + w/ 2) / w;
if(page < 0) page = 0;
if(page >= 3) page = 2;
page--;
if(page == 0) return; /*Remained on the center page*/
/*Hide all children to have clean start*/
lv_obj_t * child;
uint32_t i;
for(i = 0; i < child_cnt; i++) {
child = lv_obj_get_child(cont, i);
lv_obj_add_flag(child, LV_OBJ_FLAG_HIDDEN);
}
/*Find the new pages circularly*/
act_page_idx += page;
if(act_page_idx > (int32_t)child_cnt - 1) act_page_idx = 0;
else if(act_page_idx < 0) act_page_idx = child_cnt - 1;
int32_t prev_page_idx = act_page_idx == 0 ? (int32_t)child_cnt - 1 : act_page_idx - 1;
int32_t next_page_idx = act_page_idx == (int32_t)child_cnt - 1 ? 0 : act_page_idx + 1;
/*Add the left center and right pages to the grid*/
child = lv_obj_get_child(cont, prev_page_idx);
lv_obj_clear_flag(child, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_grid_cell(child, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
child = lv_obj_get_child(cont, act_page_idx);
lv_obj_clear_flag(child, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_grid_cell(child, LV_GRID_ALIGN_CENTER, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
child = lv_obj_get_child(cont, next_page_idx);
lv_obj_clear_flag(child, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_grid_cell(child, LV_GRID_ALIGN_CENTER, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1);
/*Scroll to the new center object*/
child = lv_obj_get_child(cont, act_page_idx);
lv_obj_scroll_to_view(child, LV_ANIM_OFF);
}
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 400, 300);
lv_obj_add_flag(cont, LV_OBJ_FLAG_SCROLL_ONE); /*Allow max 1 page swipe*/
lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_CENTER); /*Snap a page to the center*/
lv_obj_add_event_cb(cont, scroll_end_event, LV_EVENT_SCROLL_END, NULL);
/*A grid for the left center and right pages*/
static lv_coord_t col_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc);
/*Create 5 pages*/
for(int i = 0; i < 5; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, lv_pct(100), lv_pct(100));
lv_obj_t * label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Page %d", i);
}
/*Page 2, 3 hidden, page 4, 0, 1 are placed to the grid */
lv_obj_add_flag(lv_obj_get_child(cont, 2), LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(lv_obj_get_child(cont, 3), LV_OBJ_FLAG_HIDDEN);
lv_obj_set_grid_cell(lv_obj_get_child(cont, 4), LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
lv_obj_set_grid_cell(lv_obj_get_child(cont, 0), LV_GRID_ALIGN_CENTER, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
lv_obj_set_grid_cell(lv_obj_get_child(cont, 1), LV_GRID_ALIGN_CENTER, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1);
/*Be sure page 0 is centered*/
lv_obj_scroll_to_view(lv_obj_get_child(cont, 0), LV_ANIM_OFF);