在 LVGL 中c;颜色以结构 <code>lv_color_tcode> 表示。在最开始移植整个工程时c;曾经在 <code>lv_conf.hcode> 中修改过颜色深度:
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/ #define LV_COLOR_DEPTH 32
LVGL 会自动根据所选的颜色深度创建合适的颜色结构。在接下来几处位置还有几个与颜色有关的配置选项c;可以参照注释修改。
例如c;16 位 big-endian 的颜色定义为:
typedef union { struct { uint16_t blue : 5; uint16_t green : 6; uint16_t red : 5; } ch; uint16_t full; } lv_color16_t; typedef lv_color16_t lv_color_t;
那么就可以根据该结构创建合适的颜色值了:
lv_color_t orange = { .ch = { .red = 0b11111, .green = 0b101001, .blue = 0 } };
直接创建 RGB565 的颜色格式有点难以调色c;不过可以借用以下函数从十六位颜色中生成合适的颜色值:
lv_color_t orange = lv_color_make(0xFF, 0xA5, 0); // 从颜色通道创建 lv_color_t aqua = lv_color_hex(0x00FFFF); // 从十六进制创建 lv_color_t lightgrey = lv_color_hex3(0xddd); // 从十六进制简写创建
这些颜色在创建时c;每种颜色通道的值都使用 0~255 表示即可c;创建过程中会自动转换为合适的颜色值。
LVGL 还提供了 HSV 格式的颜色支持c;
lv_color_t red = lv_color_hsv_to_rgb(0, 100, 100); // 从 HSV 颜色空间创建颜色 lv_color_hsv_t blue = lv_color_rgb_to_hsv(r, g, b); // 将 RGB 颜色转换为 HSV 颜色
除此之外c;<code>lv_color_tcode> 、RGB 颜色、HSV 颜色之间也能互相转换。
如果觉得 16 进制的颜色还是不够直观c;还可以使用调色板功能。LVGL 提供了常用颜色的色值表示c;可以直接使用、微调、混合这些颜色。
例如c;以下直接调出了一个紫色:
lv_color_t purple = lv_palette_main(LV_PALETTE_PURPLE)
如果觉得默认的紫色太深或太浅的话c;还可以在调色板中更改亮度:
lv_color_t dark_purple = lv_palette_darken(LV_PALETTE_PURPLE, 2) // 调深两级c;最多可以调深或浅 4 级 lv_color_t light_purple = lv_color_lighten(purple, 60); // 调浅一些c;调到 255 就变成纯白
甚至还可以将两种颜色混合:
lv_color_t orange = lv_color_mix(red, yellow, 156);
比例的取值为 0~255 c;例如设定为 0 就是全红c;128 就是红黄各占一半等。
可以将一个颜色类型直接应用到以下样式属性中:
属性名 | 含义 |
---|---|
<code>bg_colorcode> | 背景颜色 |
<code>border_colorcode> | 边框颜色 |
<code>outline_colorcode> | 轮廓颜色 |
<code>shadow_colorcode> | 阴影颜色 |
<code>text_colorcode> | 文本颜色 |
以及上一节提到的直线和弧线颜色。
有时候两个控件间可能发生重叠c;这个时候就可以给它们设置一个透明度。
透明度使用类型 <code>lv_opa_tcode> 表示c;LVGL 预定义了几个表示透明度的宏:<code>LV_OPA_TRANSPcode> 表示完全透明c;<code>LV_OPA_COVER code>表示完全不透明c;其余的 <code>LV_OPA_10 code>~ <code>LV_OPA_90 code>整十表示的透明度依次递减。
可以将透明度应用到以下样式属性中:
属性名 | 含义 |
---|---|
<code>bg_opacode> | 背景透明度 |
<code>border_opacode> | 边框透明度 |
<code>outline_opacode> | 轮廓透明度 |
<code>shadow_opacode> | 阴影透明度 |
<code>text_opacode> | 文本透明度 |
<code>opacode> | 整体透明度 |
以及直线和弧线透明度。例如c;以下创建了两个部分重叠的控件c;并在一个的背景上加透明度:
static lv_style_t style_grass; lv_style_init(&style_grass); lv_style_set_opa(&style_grass, LV_OPA_30); lv_obj_t* obj = lv_obj_create(lv_scr_act()); lv_obj_t* cover = lv_obj_create(lv_scr_act()); lv_obj_add_style(cover, &style_grass, 0);
这样就可以看见被遮挡的控件了:
注意需要给上层c;即后创建的的控件加透明度才会有这样的效果。透明度其实就是为控件重新调色c;因此不是 32 位颜色的屏幕也可以使用透明度。
<code>lv_opa_tcode> 类型的本质就是 8 位无符号整数c;因此可以自行创建一个透明度数值c;设为 255 就代表完全透明;还可以将透明度应用到 <code>lv_color_mix()code> 的第三个参数上。
可以使用渐变色给控件加上更美观的效果。
只有背景颜色能设置渐变色。一个渐变色的效果由以下几个属性支配:
属性名 | 含义 |
---|---|
<code>bg_colorcode> | 主要颜色 |
<code>bg_grad_colorcode> | 渐变颜色 |
<code>bg_grad_dircode> | 渐变方向 |
<code>bg_main_stopcode> | 渐变开始位置 |
<code>bg_grad_stopcode> | 渐变结束位置 |
<code>bg_dither_modecode> | 渲染模式 |
当确定了渐变方向后c;渐变从 <code>bg_main_stopcode> 位置开始c;由 <code>bg_colorcode> 过度到 <code>bg_grad_colorcode> c;在 <code>bg_grad_stopcode> 位置结束。这里的位置是由比例衡量的c;渐变区域在每个方向都被划分为 256 份c;例如 128 代表中间位置c;255 代表结束位置等。
例如c;以下代码:
lv_obj_t* obj01 = lv_obj_create(lv_scr_act()); lv_obj_set_style_bg_color(obj01, lv_palette_main(LV_PALETTE_BLUE), 0); lv_obj_set_style_bg_grad_color(obj01, lv_palette_main(LV_PALETTE_RED), 0); lv_obj_set_style_bg_grad_dir(obj01, LV_GRAD_DIR_HOR, 0);
渐变效果为水平方向从蓝色一直渐变到红色:
再如c;以下代码:
lv_obj_t* obj02 = lv_obj_create(lv_scr_act()); lv_obj_set_style_bg_color(obj02, lv_palette_main(LV_PALETTE_GREEN), 0); lv_obj_set_style_bg_grad_color(obj02, lv_palette_main(LV_PALETTE_PURPLE), 0); lv_obj_set_style_bg_grad_stop(obj02, 128, 0); lv_obj_set_style_bg_grad_dir(obj02, LV_GRAD_DIR_VER, 0);
渐变效果为竖直方向从绿色一直渐变到紫色c;但实际渐变区域只有上半部分:
还可以使用简写属性 <code>bg_gradcode> 设置完整的渐变属性。这种情况下c;渐变使用结构 <code>lv_grad_dsc_tcode> 描述:
typedef struct { lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; uint8_t stops_count; lv_grad_dir_t dir : 3; lv_dither_mode_t dither : 3; } lv_grad_dsc_t;
宏 <code>LV_GRADIENT_MAX_STOPScode> 决定了最大拥有的渐变颜色数c;可以在 <code>lv_conf_internal.hcode> 大约 377 行修改该宏的数量:
#ifndef LV_GRADIENT_MAX_STOPS #ifdef CONFIG_LV_GRADIENT_MAX_STOPS #define LV_GRADIENT_MAX_STOPS CONFIG_LV_GRADIENT_MAX_STOPS #else #define LV_GRADIENT_MAX_STOPS 3 #endif #endif
然后就可以自定义多种颜色的渐变了:
static lv_grad_dsc_t grad_sunset; grad_sunset.stops[0] = (lv_gradient_stop_t){ .color = lv_palette_main(LV_PALETTE_RED), .frac = 96 }; grad_sunset.stops[1] = (lv_gradient_stop_t){ .color = lv_palette_main(LV_PALETTE_ORANGE), .frac = 128 }; grad_sunset.stops[2] = (lv_gradient_stop_t){ .color = lv_palette_main(LV_PALETTE_BLUE), .frac = 216 }; grad_sunset.stops_count = 3; grad_sunset.dir = LV_GRAD_DIR_VER; lv_obj_t* obj03 = lv_obj_create(lv_scr_act()); lv_obj_set_style_bg_grad(obj03, &grad_sunset, 0);
效果为:
LVGL 还提供了许多处理颜色的滤镜。可以使用样式属性 <code>blend_modecode> 设置颜色和背景色的融合。例如c;以下将控件的颜色设置为背景色的反色:
lv_obj_set_style_blend_mode(obj03, LV_BLEND_MODE_SUBTRACTIVE, 0);
效果为:
注意边框的颜色也变成反色了。
最后c;LVGL 中还要一个控件 color wheel c;可以快速创建一个颜色选择器。它的默认表现形式为:
它类似于圆弧c;并可以通过长按切换模式。可以使用函数 <code>lv_colorwheel_get_rgb()code> 获取当前选择的颜色。
图片可以以两种方式存储:一是作为一个数组之类的变量c;二是通过二进制文件的形式存储。由于还没有介绍文件相关的内容c;这里仅介绍使用数组的方式来存储并使用图片。
LVGL 已经提供了在线图片转换器c;可以直接在 Online image converter - BMP, JPG or PNG to C array or binary | LVGL 将一般的 PNG 或 JPG 图片转换为符合要求的 C 语言对象:
注意转换完成后得到的是一个完整的源文件c;文件名同时也是图片的变量名。以上唯一值的注意的一点是图片所用的颜色格式c;一般来说颜色格式可以分为以下几类:
最后一个 RBG565-A8 就不必多说了。值的注意的是c;以上有一种叫“Chroma key” 的颜色格式c;它对应 <code>lv_conf.hcode> 的第 42 行的配置c;注释是这样说的:
/*Images pixels with this color will not be drawn if they are chroma keyed)*/ #define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/
更多有关于此的介绍可以阅读维基百科 https://en.wikipedia.org/wiki/Chroma_key
转换完成后c;将得到的源文件添加到当前工程内c;然后通过以下几行代码就可以显示该图像:
LV_IMG_DECLARE(class="tags" href="/tags/LVGL.html" title=lvgl>lvgl_logo); lv_obj_t* img01 = lv_img_create(lv_scr_act()); lv_img_set_src(img01, &class="tags" href="/tags/LVGL.html" title=lvgl>lvgl_logo);
这里第一个宏的作用本质就是一个 <code>externcode> 语句。显示的效果为:
注意这里在模拟器上创建的图片是具有透明度的。
像直线和圆弧一样c;图片对象也是有特殊的属性的c;不过比较少:
属性 | 简介 |
---|---|
<code>img_opacode> | 图片透明度 |
<code>img_recolorcode> | 可以给图片加上一层颜色滤镜 |
<code>img_recolor_opacode> | 这层滤镜的透明度 |
默认情况下c;图片控件会自动调整宽度以适应图片大小。如果控件过小c;那么图片的额外部分会被去除;如果控件过大c;那么图片会像地砖一样重复铺开来填补剩下的区域。
可以通过 <code>lv_img_set_offset_x(img, x_ofs)code> 与 y 轴对应的函数给图片设置一个偏移量来修改显示范围。例如c;可以通过偏移量结合控件宽度来裁剪图片:
lv_img_set_offset_x(img01, -2); lv_img_set_offset_y(img01, -7); lv_obj_set_size(img01, 74, 74);
这里通过负值来将图片向左上角偏移c;从而框选出合适的区域:
最后再介绍一个内容c;可以通过图片来创建一个按钮。这种情况下c;需要准备三张图片c;分别描述按钮的左边、中间和右边。
例如c;以下准备图片如下:
由于标签的宽度是不确定的c;因此中间的图片必须是水平可平铺的。将其转换为对应的图片格式后c;可以通过以下代码创建一个图片按钮:
lv_obj_t* imgbtn = lv_imgbtn_create(lv_scr_act()); lv_imgbtn_set_src(imgbtn, LV_IMGBTN_STATE_RELEASED, &imgbtn_left, &imgbtn_mid, &imgbtn_right); lv_obj_t* label = lv_label_create(imgbtn); lv_label_set_text(label, "Image Button"); lv_obj_set_style_img_recolor_opa(imgbtn, LV_OPA_30, LV_STATE_PRESSED); lv_obj_set_style_img_recolor(imgbtn, lv_color_black(), LV_STATE_PRESSED);
注意在创建的过程中c;将以上图片应用到按钮的普通状态(即什么事件都没有的状态)的外观中。这里通过给点击事件加上一层深色的滤镜使点击时外观可以发生改变:
这样按钮就可以变得很花哨了。
以上对于图片的介绍比较简单c;不过也基本足以应付一般的使用场景了。更多细节可以参考官方文档。
Colors — LVGL documentation
颜色参考文档
https://docs.class="tags" href="/tags/LVGL.html" title=lvgl>lvgl.io/master/overview/image.html
https://docs.class="tags" href="/tags/LVGL.html" title=lvgl>lvgl.io/master/widgets/core/img.html
有关图片及图片控件的完整使用描述