Align Grid within lv_obj_t

What do you want to achieve?

I am hoping to center a grid within the screen / lv_obj_t but cannot seem to figure out how. I have two grids, one with three rollers and a button (its boarder is still visible in the screen shot showing the container is aligned) and another with three buttons both are left aligned within their containers. The containers themselves I was able to align to the center of the screen using lv_obj_align but the elements within the grid I havent been able to align.

I have seen a work around of using either margin or offsets to manually force things over but wanted to see if there is a cleaner option.

What have you tried so far?

  • lv_obj_align(object_in_grid, LV_ALIGN_CENTER, 0, 0);
  • lv_obj_set_grid_cell(object_in_grid, LV_GRID_ALIGN_CENTER, 0, 0, LV_GRID_ALIGN_CENTER, 0, 0);
  • lv_obj_center(grid_container);

Code to reproduce

void setup_ui(lv_obj_t *parent) {
    lv_obj_set_style_bg_color(parent, lv_color_black(), LV_STATE_DEFAULT);

    // Top status bar
    static lv_style_t statusBarStyle;
    lv_style_init(&statusBarStyle);
    lv_style_set_bg_color(&statusBarStyle, lv_color_hex(0xBDBDBD));
    lv_style_set_radius(&statusBarStyle, 0);
    lv_style_set_border_width(&statusBarStyle, 0);

    lv_obj_t *statusBar = lv_obj_create(parent);
    lv_obj_set_size(statusBar, lv_pct(100), 30);
    lv_obj_align(statusBar, LV_ALIGN_TOP_MID, 0, 0);
    lv_obj_add_style(statusBar, &statusBarStyle, LV_PART_MAIN);

    // Create status bar icons
    lv_obj_t *settingsButton = lv_btn_create(statusBar);
    static lv_style_t settingsButtonStyle;
    lv_style_init(&settingsButtonStyle);
    lv_style_set_bg_color(&settingsButtonStyle, lv_color_hex(0xBDBDBD));
    lv_style_set_radius(&settingsButtonStyle, 0);
    lv_style_set_border_width(&settingsButtonStyle, 0);
    lv_style_set_margin_left(&settingsButtonStyle, 0);
    lv_obj_add_style(settingsButton, &settingsButtonStyle, LV_PART_MAIN);
    lv_obj_t *settingsLabel = lv_label_create(settingsButton);
    lv_label_set_text(settingsLabel, LV_SYMBOL_SETTINGS); // Replace with an actual icon in a real application
    lv_obj_set_style_bg_color(settingsLabel, lv_color_black(), LV_STATE_DEFAULT);
    lv_obj_align(settingsButton, LV_ALIGN_LEFT_MID, 0, 0); // Adjust alignment for spacing

    lv_obj_t *connectionIcon = lv_label_create(statusBar);
    lv_label_set_text(connectionIcon, LV_SYMBOL_HOME " Connected"); // Replace with an actual icon in a real application
    lv_obj_align(connectionIcon, LV_ALIGN_CENTER, 0, 0); // Adjust alignment for spacing

    lv_obj_t *wifiIcon = lv_label_create(statusBar);
    lv_label_set_text(wifiIcon, LV_SYMBOL_WIFI); // Replace with an actual icon in a real application
    lv_obj_align(wifiIcon, LV_ALIGN_RIGHT_MID, -15, 0); // Adjust left of connection icon

    lv_obj_t *batteryIcon = lv_label_create(statusBar);
    lv_label_set_text(batteryIcon, LV_SYMBOL_CHARGE); // Replace with a dynamic battery percentage in a real application
    lv_obj_align(batteryIcon, LV_ALIGN_RIGHT_MID, 0, 0); // Adjust left of wifi icon

    static int32_t mainGridColumns[] = {lv_pct(100), LV_GRID_TEMPLATE_LAST};
    static int32_t mainGridRows[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
    lv_obj_t *mainGridContainer = lv_obj_create(parent);
    lv_obj_set_style_grid_column_dsc_array(mainGridContainer, mainGridColumns, 0);
    lv_obj_set_style_grid_row_dsc_array(mainGridContainer, mainGridRows, 0);
    lv_obj_set_layout(mainGridContainer, LV_LAYOUT_GRID);
    lv_obj_set_size(mainGridContainer, lv_pct(100), 200);   // UPDATE ME
    lv_obj_align(mainGridContainer, LV_ALIGN_TOP_MID, 0, 30);
    lv_obj_set_style_border_width(mainGridContainer, 0, LV_STATE_DEFAULT);
    lv_obj_set_style_margin_all(mainGridContainer, 0, LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(mainGridContainer, lv_color_black(), LV_STATE_DEFAULT);

    lv_obj_t *mainLabel = lv_label_create(mainGridContainer);
    lv_label_set_text(mainLabel, "Scan for info"); // Replace with an actual icon in a real application
    lv_obj_set_style_text_color(mainLabel, lv_color_white(), 0);
    lv_obj_set_style_text_font(mainLabel, &lv_font_montserrat_36 , LV_STATE_DEFAULT);
    lv_obj_set_style_text_align(mainLabel, LV_TEXT_ALIGN_CENTER, 0);
    lv_obj_set_grid_cell(mainLabel, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
    lv_obj_center(mainLabel);

    // Table in the middle half of the UI
    lv_obj_t *table = lv_table_create(mainGridContainer);
    lv_table_set_col_cnt(table, 2);
    lv_table_set_row_cnt(table, 2);
    lv_obj_set_grid_cell(table, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 1, 1);
    lv_obj_center(table);
    lv_obj_set_style_bg_color(table, lv_color_black(), LV_PART_ITEMS);
    lv_obj_set_style_border_color(table, lv_color_white(), LV_PART_MAIN|LV_PART_ITEMS);
    lv_obj_set_style_border_width(table, 1, LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(table, lv_color_white(), LV_PART_MAIN|LV_PART_ITEMS);

    // Fill table with example content
    lv_table_set_cell_value(table, 0, 0, "UPC");
    lv_table_set_cell_value(table, 0, 1, "123456");
    lv_table_set_cell_value(table, 1, 0, "Quantity");
    lv_table_set_cell_value(table, 1, 1, "2");

    // ---------------- Rollers that should be centered ----------------------------------------
    static int32_t rollerGridColumns[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
    static int32_t rollerGridRows[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
    lv_obj_t *rollersContainer = lv_obj_create(parent);
    lv_obj_set_style_grid_column_dsc_array(rollersContainer, rollerGridColumns, 0);
    lv_obj_set_style_grid_row_dsc_array(rollersContainer, rollerGridRows, 0);
    lv_obj_set_style_margin_all(rollersContainer, 0, LV_STATE_DEFAULT);
    lv_obj_align(rollersContainer, LV_ALIGN_BOTTOM_MID, 0, -100);
    lv_obj_set_width(rollersContainer, lv_pct(100));
    lv_obj_clear_flag(rollersContainer, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_style_bg_color(rollersContainer, lv_color_black(), LV_STATE_DEFAULT);
    lv_obj_set_layout(rollersContainer, LV_LAYOUT_GRID);

    const char * numberOptions = "9\n8\n7\n6\n5\n4\n3\n2\n1\n0";
    lv_obj_t * hundredsRoller = lv_roller_create(rollersContainer);
    lv_roller_set_visible_row_count(hundredsRoller, 3);
    lv_roller_set_options(hundredsRoller, numberOptions, LV_ROLLER_MODE_NORMAL);
    lv_roller_set_selected(hundredsRoller, 9, LV_ANIM_OFF);
    lv_obj_set_width(hundredsRoller, 60);
    lv_obj_align(hundredsRoller, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_grid_cell(hundredsRoller, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);    
    lv_obj_t * tensRoller = lv_roller_create(rollersContainer);
    lv_roller_set_visible_row_count(tensRoller, 3);
    lv_roller_set_options(tensRoller, numberOptions, LV_ROLLER_MODE_NORMAL);
    lv_roller_set_selected(tensRoller, 9, LV_ANIM_OFF);
    lv_obj_set_width(tensRoller, 60);
    lv_obj_align(tensRoller, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_grid_cell(tensRoller, LV_GRID_ALIGN_CENTER, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);    
    lv_obj_t * onesRoller = lv_roller_create(rollersContainer);
    lv_roller_set_visible_row_count(onesRoller, 3);
    lv_roller_set_options(onesRoller, numberOptions, LV_ROLLER_MODE_NORMAL);
    lv_roller_set_selected(onesRoller, 8, LV_ANIM_OFF);
    lv_obj_set_width(onesRoller, 60);
    lv_obj_align(onesRoller, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_grid_cell(onesRoller, LV_GRID_ALIGN_CENTER, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1);    

    lv_obj_t *resetButton = lv_btn_create(rollersContainer);
    lv_obj_align(resetButton, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_grid_cell(resetButton, LV_GRID_ALIGN_CENTER, 3, 1, LV_GRID_ALIGN_CENTER, 0, 1);    
    lv_obj_t *resetLabel = lv_label_create(resetButton);
    lv_label_set_text_static(resetLabel, LV_SYMBOL_REFRESH);
    lv_obj_set_style_text_font(resetLabel, &lv_font_montserrat_28 , LV_STATE_DEFAULT);
    lv_obj_center(resetLabel);

    // Bottom buttons
    static int32_t col_dsc[] = {75, 75, 75, LV_GRID_TEMPLATE_LAST};
    static int32_t row_dsc[] = {75, 75, 75, LV_GRID_TEMPLATE_LAST};
    lv_obj_t *buttonContainer = lv_obj_create(parent);
    lv_obj_set_style_grid_column_dsc_array(buttonContainer, col_dsc, 0);
    lv_obj_set_style_grid_row_dsc_array(buttonContainer, row_dsc, 0);
    lv_obj_set_style_border_width(buttonContainer, 0, LV_STATE_DEFAULT);
    lv_obj_set_style_margin_all(buttonContainer, 0, LV_STATE_DEFAULT);
    lv_obj_set_size(buttonContainer, lv_pct(100), LV_SIZE_CONTENT);
    lv_obj_align(buttonContainer, LV_ALIGN_BOTTOM_MID, 0, 0);
    lv_obj_clear_flag(buttonContainer, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_set_style_bg_color(buttonContainer, lv_color_black(), LV_STATE_DEFAULT);
    lv_obj_set_layout(buttonContainer, LV_LAYOUT_GRID);

    // Create buttons
    lv_obj_t *set_btn = lv_btn_create(buttonContainer);
    lv_obj_set_grid_cell(set_btn, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_STRETCH, 0, 1);    
    lv_obj_t *add_btn = lv_btn_create(buttonContainer);
    lv_obj_set_grid_cell(add_btn, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_STRETCH, 0, 1);  
    lv_obj_t *remove_btn = lv_btn_create(buttonContainer);
    lv_obj_set_grid_cell(remove_btn, LV_GRID_ALIGN_STRETCH, 2, 1, LV_GRID_ALIGN_STRETCH, 0, 1);  

    // Set button labels
    lv_obj_t *setLabel = lv_label_create(set_btn);
    lv_label_set_text_static(setLabel, "Set");
    lv_obj_set_style_text_font(setLabel, &lv_font_montserrat_28 , LV_STATE_DEFAULT);
    lv_obj_center(setLabel);

    lv_obj_t *addLabel = lv_label_create(add_btn);
    lv_label_set_text_static(addLabel, "Add");
    lv_obj_set_style_text_font(addLabel, &lv_font_montserrat_28 , LV_STATE_DEFAULT);
    lv_obj_center(addLabel);

    lv_obj_t *removeLabel = lv_label_create(remove_btn);
    lv_label_set_text_static(removeLabel, "Sub.");
    lv_obj_set_style_text_font(removeLabel, &lv_font_montserrat_28 , LV_STATE_DEFAULT);
    lv_obj_center(removeLabel);

    // Equally space buttons - Set width and expansion
    lv_obj_set_width(set_btn, lv_pct(33));
    lv_obj_set_width(add_btn, lv_pct(33));
    lv_obj_set_width(remove_btn, lv_pct(33));
}

Screenshot and/or video

Environment

  • MCU/MPU/Board: ESP32 (CYD35)
  • LVGL version: 9.1

This should be all you need:

lv_obj_set_grid_align(rollersContainer, LV_GRID_ALIGN_CENTER, LV_GRID_ALIGN_CENTER);

and

lv_obj_set_grid_align(buttonContainer, LV_GRID_ALIGN_CENTER, LV_GRID_ALIGN_CENTER);

This is the documentation about it: Grid — LVGL documentation