Gradient with transparency in LVGL v8.4

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

Custom board with a STM32H753 MCU

What LVGL version are you using?

Latest v8.4 release

What do you want to achieve?

I’d like to create a vertical gradient with the same size of the full screen which goes from transparent to full black; however if I’m understanding correctly alpha is supported for colors only when using LV_COLOR_DEPTH set as 32 (which is currently 16 for my application). Is there a way to do that anyway? I’ve looked and in LVGL V9 there is the lv_obj_set_style_bg_grad_opa function which seems to implement this kind of gradient, is this correct?

I did manage to implement a solution, however the results are underwhelming due to the low gamma of the display.

I implemented it by adding a simple rectangle with a custom draw function; the idea was taken by one of the chart examples which had a gradient under the graph lines.

static lv_style_t grad_style;
static lv_obj_t *grad;

void init_grad()
{
    lv_style_init(&grad_style);
    lv_style_set_pad_all(&grad_style, 0);
    lv_style_set_border_width(&grad_style, 0);
    lv_style_set_radius(&grad_style, 0);
    lv_style_set_bg_color(&grad_style, lv_color_hex(COLOR_BLACK));

    grad = lv_obj_create(lv_layer_top());
    lv_obj_set_scrollbar_mode(grad, LV_SCROLLBAR_MODE_OFF);
    lv_obj_set_size(grad, SCREEN_WIDTH, SCREEN_HEIGHT);
    lv_obj_set_pos(grad, 0, 0);
    lv_obj_add_style(grad, &grad_style, LV_PART_MAIN);
    lv_obj_set_style_bg_opa(grad, LV_OPA_0, LV_PART_MAIN);
    lv_obj_add_event_cb(grad, gradient_draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
}

/* Custom draw function */
static void gradient_draw_event_cb(lv_event_t *e)
{
    lv_obj_t *obj = lv_event_get_target(e);
    lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e);

    if (dsc->part == LV_PART_MAIN)
    {
        lv_draw_mask_fade_param_t fade_mask_param;
        lv_draw_mask_fade_init(&fade_mask_param, &obj->coords, LV_OPA_TRANSP, obj->coords.y1, LV_OPA_COVER,
                               obj->coords.y2);
        int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, NULL);

        lv_draw_rect_dsc_t draw_rect_dsc;
        lv_draw_rect_dsc_init(&draw_rect_dsc);
        draw_rect_dsc.bg_opa   = LV_OPA_100;
        draw_rect_dsc.bg_color = lv_obj_get_style_bg_color(obj, dsc->part);

        lv_area_t a;
        a.x1 = obj->coords.x1;
        a.x2 = obj->coords.x2;
        a.y1 = obj->coords.y1;
        a.y2 = obj->coords.y2;
        lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);

        lv_draw_mask_free_param(&fade_mask_param);
        lv_draw_mask_remove_id(fade_mask_id);
    }
}

Maybe simpler and more flex is place png alpha image over screen. Image require only full size in direction for gradient for example 8x240px … LVGL tile copy it to set size.

That would be another idea, I didn’t know LVGL could tile images while keeping them in memory only one time