The screen 1, 2 and 3 are created but I am having trouble achieving this flow. Where should I call the next function ? I cannot do it in main as lv_task_handler() is being called in a while(1) loop.
If someone can share some already written code for their project maybe I can take notes from it.
This is more of an architectural question than one that I can provide a direct sample to.
Like I said before, one way of approaching it (but this is not the only one) is that you have functions for creating screens 1, 2, and 3. When LittlevGL starts, you manually create screen 1 (and all its child objects), and set it as the root object using lv_scr_load. You then delete whatever the previous screen was.
lv_obj_t * next_scr = create_screen2();
lv_obj_t * prev_scr = lv_scr_act();
lv_scr_load(next_scr);
lv_obj_del_async(prev_scr); /*not sure if async is needed here or not */
Inside LV_EVENT_CLICKED handlers registered on the buttons, you basically do the same thing, but obviously you would create different screens.
There are several ways you can approach the problem. I can’t provide a more specific code example without some more information about what result you’re looking to get. Do you need a transition between screens, or is an instant flip like this acceptable? How much memory do you have? Can you afford to store three screens in RAM (to avoid needing to recreate them each time) or are you constrained to only having one in RAM at a time?
static void ok_event_handler(lv_obj_t * obj, lv_event_t event)
{
if(event == LV_EVENT_CLICKED)
{
lv_obj_t * next_scr = create_screen2();
lv_obj_t * prev_scr = lv_scr_act();
lv_scr_load(next_scr);
lv_obj_del_async(prev_scr);
}
}
void create_screen_1()
{
//Some code to create objects on current active screen
lv_obj_t *ok_btn = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(ok_btn, ok_event_handler);
//Something same to create a cancel button but with a separate event handler
//Create a label showing this string
lv_obj_t *label;
label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "Put a NFC card below the device to read data from it" );
}
create_screen_2.c
static void ok_event_handler(lv_obj_t * obj, lv_event_t event)
{
if(event == LV_EVENT_CLICKED)
{
lv_obj_t * next_scr = create_screen3();
lv_obj_t * prev_scr = lv_scr_act();
lv_scr_load(next_scr);
lv_obj_del_async(prev_scr);
}
}
static void cancel_event_handler(lv_obj_t * obj, lv_event_t event)
{
if(event == LV_EVENT_CLICKED)
{
lv_obj_t * next_scr = create_screen1();
lv_obj_t * prev_scr = lv_scr_act();
lv_scr_load(next_scr);
lv_obj_del_async(prev_scr);
}
}
lv_obj_t * create_screen_2()
{
lv_obj_t *scr;
//Some code to create objects on current active screen
lv_obj_t *ok_btn = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(ok_btn, ok_event_handler);
//Creating cancel button
lv_obj_t *cancel_btn = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_event_cb(canel_btn, cancel_event_handler);
//Do some computations
//Suppose I have a nfc reader and I want to display data read from it
char string[1024];
string = read_data_from_nfc();
//Create a label showing this string
lv_obj_t *label;
label = lv_label_create(scr, NULL);
lv_label_set_text(label, string);
return scr;
}
Is this how you are suggesting to code ?
Thank you for your help. You have been very helpful.
Again, this type of question depends on the exact transition you’re looking for. Do you want to fade in/out? Do you want a sliding effect? You’ll need to provide more details.
Thank you for your attention, a sliding effect is what I want. I’m still evaluating this GUI, maybe I can do other effects myself if a sliding effect is possible.
The easiest way to get a sliding effect for free is to make use of the tabview but hide the buttons. You can then flip between screens with lv_tabview_set_tab_act. If you needed to save memory you could dynamically populate each tab as you switch to it.
lv_obj_t * tabview;
void btn_event_cb(lv_obj_t * btn, lv_event_t event)
{
if(event == LV_EVENT_CLICKED) {
lv_tabview_set_tab_act(tabview, (uint16_t)lv_obj_get_user_data(btn), LV_ANIM_ON);
}
}
void test_screens(void)
{
tabview = lv_tabview_create(lv_scr_act(), NULL);
lv_tabview_set_btns_hidden(tabview, true);
lv_tabview_set_sliding(tabview, false);
/* Screen 1 */
lv_obj_t * scr1 = lv_tabview_add_tab(tabview, "scr1");
lv_obj_t * btn = lv_btn_create(scr1, NULL);
lv_obj_set_user_data(btn, (lv_obj_user_data_t)1); /* Store the next screen ID in user data */
lv_obj_set_event_cb(btn, btn_event_cb);
lv_obj_t * label = lv_label_create(btn, NULL);
lv_label_set_text(label, "Flip to Screen 2");
/* Screen 2 */
lv_obj_t * scr2 = lv_tabview_add_tab(tabview, "scr2");
btn = lv_btn_create(scr2, NULL);
lv_obj_set_user_data(btn, (lv_obj_user_data_t)0); /* Store the next screen ID in user data */
lv_obj_set_event_cb(btn, btn_event_cb);
label = lv_label_create(btn, NULL);
lv_label_set_text(label, "Flip to Screen 1");
}
Thank you for your support, I found that “tabview” can only slide horizontally, even after setting LV_TABVIEW_BTNS_POS_LEFT. Is there any APIs can change the sliding direction? Or should I create a new “page” object to show the screen of another app?
Is that to say the object “screen” does not designed for showing screens of different applications, but for multi LCD?
I don’t believe you can change the sliding direction of the tabview at the moment, but it would definitely be a reasonable feature.
It is designed to show different screens of applications, but there is no built-in transition support.
Another option, if you want more flexibility over the sliding, is to manually create a container and put two full screen objects inside, and use animations to move them up and down as required. The object hierarchy would look like this:
scr
| - container
| - screen1
| - screen2
Then you could move “container” up and down with an animation to make screen1 and screen2 visible.