Tab View: circular scrolling

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. :slight_smile:


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);

1 Like