Is it possible to add a "go back" button alongside tab headers in a tab view?

Description

What MCU/Processor/Board and compiler are you using?

SDL simulator.

What do you want to achieve?

I’d like to put a “back” button on the top left corner of a tabview, just beside the first tab header. I could achieve something similar by going back when the first tab is selected and give it an appropriate name/symbol, but I was wondering if there was a more direct way to achieve it.

What have you tried so far?

I placed a button above the tabview, in the position I wish it to be; it works, but the tab headers should be shifted right, otherwise the first one is covered.

Code to reproduce


    lv_obj_t *tabview = lv_tabview_create(lv_scr_act(), NULL);

    lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "tab1");
    lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "tab2");
    lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "tab3");

    lv_obj_t *btn = lv_btn_create(tabview, NULL);
    lv_obj_t *lbl = lv_label_create(btn, NULL);
    lv_label_set_text(lbl, "back");
    lv_obj_align(btn, tabview, LV_ALIGN_IN_TOP_LEFT, 0, 0);

Screenshot and/or video

Placing the button and the tabview inside a container with the appropriate layout configuration would be what I would try.

I can achieve something similar with layout configuration: tabview and button however are placed side by side and as a result the tab content suffers an horizontal cut in the available space.

In the end I resorted to fiddling with the external attributes of the tabview to reach exactly the goal I had in mind:

And here is the code I used:

    lv_tabview_ext_t *ext        = lv_obj_get_ext_attr(tabview);
    const lv_style_t *style_tabs = lv_obj_get_style(ext->btns);
    lv_obj_set_auto_realign(ext->btns, 1);
    lv_obj_align(ext->btns, NULL, LV_ALIGN_IN_TOP_LEFT, 50, 0);
    lv_obj_set_width(ext->btns, LV_HOR_RES_MAX - 50);
    int indic_size = (lv_obj_get_width(ext->btns) - style_tabs->body.padding.inner * (ext->tab_cnt - 1) -
                      style_tabs->body.padding.left - style_tabs->body.padding.right) /
                     ext->tab_cnt;
    lv_obj_set_width(ext->indic, indic_size);

    lv_obj_t *btn = build_button_id(tabview, BACK_BTN);
    lv_obj_t *lbl = lv_label_create(btn, NULL);
    lv_label_set_text(lbl, LV_SYMBOL_LEFT);
    lv_obj_set_size(btn, 46, 46);
    lv_obj_align(btn, tabview, LV_ALIGN_IN_TOP_LEFT, 4, 4);

As a follow up question, what’s LVGL’s official stance on directly fiddling with external attributes? I believe I read somewhere that internal functioning is not guaranteed if you do, but I believe I did (or that I can do eventually) my homework properly when cooking up this hack. Thoughts?

Of course, provided that you know what you’re doing and you’re willing to live with potential breakage in new releases, we don’t explicitly ban doing that either, particularly for custom things like this. It’s just not a good practice to apply to your whole program, because it will make maintenance impossible/really difficult.

1 Like

Wouldn´t it be possible to add a “buffer” variable to store the last clicked tab and a back button variable and set the target tab for that button to be the tab that is stored in your variable? I guess I would make it change the variable when the tab content is loaded. So when you click a tab it stores the tab that just loaded into that variable. Then when the next tab is clicked it stores that value in the back button variable and updates the “buffer” variable.

I hope I understood your question correctly.

You can do it very easily with LV_EVENT_VALUE_CHANGED` which is triggered when a new tab is loaded. You save the ids there as you need and load the appropriate tab when the back button is clicked.

ah yes that is what I meant with buffer variable.