使用LVGL画一个表盘圆弧随指针变动的仪表
不做过多解释,直接上代码,主要原理就是利用LVGL的mask遮罩特性,先用canvas画出一个圆弧(该圆弧的弧度随着指针度数变化而变化),然后制作成遮罩,再然后把遮罩应用到图片上。
#include “../../../lv_examples.h”
#if LV_USE_IMG
LV_IMG_DECLARE(img_cogwheel_argb);
lv_obj_t * om; //随指针变化的底图遮罩
lv_obj_t * bg; //随指针变化的底图图片
lv_obj_t * imgBg; //表盘
lv_obj_t * img; //指针
lv_obj_t * label1; //速度文本
uint32_t speed = 0;
int dir=1;
uint32_t oldAngle = 1800-450;
void my_task(lv_task_t * task)
{
uint32_t * user_data = task->user_data;
speed += dir*2; //每次速度加2公里
uint32_t newAngle = 1800 – 450 + speed * 10 * 270 / 250; //整个表盘有刻度的占270度,最大250公里/小时,表盘旋转角度以1/10度为单位。
//用动画来过渡,比直接用lv_img_set_angle设置到新角度要流畅很多:
lv_anim_del_all();
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, img);
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_img_set_angle);
lv_anim_set_values(&a, oldAngle, newAngle);
lv_anim_set_time(&a, 100);
//lv_anim_set_playback_time(&a, 100);
lv_anim_start(&a);
lv_label_set_text_fmt(label1, “#ff0000 %d#”, speed);
lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, -15);
lv_objmask_remove_mask(om, NULL);
lv_obj_del(bg);
lv_obj_del(om);
arc_mask_test(newAngle/10);
//下一次的值:
oldAngle = newAngle;
if(speed>=250){
dir = -1;
}
if(speed<=0){
dir = 1;
}
}
#define MASK_WIDTH 440 //图片的宽高
#define MASK_HEIGHT 440
void arc_mask_test(uint32_t endRad) {
/* Create the mask of an arc by drawing it to a canvas*/
static lv_opa_t mask_map[MASK_WIDTH * MASK_HEIGHT];
/*Create a “8 bit alpha” canvas and clear it*/
lv_obj_t * canvas = lv_canvas_create(lv_scr_act(), NULL);
lv_canvas_set_buffer(canvas, mask_map, MASK_WIDTH, MASK_HEIGHT, LV_IMG_CF_ALPHA_8BIT);
lv_canvas_fill_bg(canvas, LV_COLOR_BLACK, LV_OPA_TRANSP);
/*Draw an arc to the canvas. The result “image” will be used as mask*/
lv_draw_line_dsc_t arc_dsc;
lv_draw_line_dsc_init(&arc_dsc);
arc_dsc.color = LV_COLOR_WHITE;
arc_dsc.width = 50;
lv_canvas_draw_arc(canvas, MASK_WIDTH / 2, MASK_HEIGHT / 2, MASK_WIDTH / 2, 180-45, endRad, &arc_dsc);//以正方形中心为中心,以1/2边长为半径,画圆弧
/*The mask is reads the canvas is not required anymore*/
lv_obj_del(canvas);
/*Create an object mask which will use the created mask*/
om = lv_objmask_create(lv_scr_act(), NULL);
lv_obj_set_size(om, MASK_WIDTH, MASK_HEIGHT);
lv_obj_align(om, NULL, LV_ALIGN_CENTER, 0, 44); //对齐到指针盘面的中心
lv_obj_move_background(om); //把它放到底图上,避免覆盖表盘和指针
/*Add the created mask map to the object mask*/
lv_draw_mask_map_param_t m;
lv_area_t a;
a.x1 = 0;
a.y1 = 0;
a.x2 = MASK_WIDTH – 1;
a.y2 = MASK_HEIGHT – 1;
lv_draw_mask_map_init(&m, &a, mask_map); //把画好的圆弧设置到遮罩
lv_objmask_add_mask(om, &m); //把遮罩设置到遮罩对象
/*Create a style with gradient*/
/* static lv_style_t style_bg;
lv_style_init(&style_bg);
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER); //静态的style 只能设置各种属性一次,这里循环设置的话则会内存泄露
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_style_set_bg_grad_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLUE);
lv_style_set_bg_grad_dir(&style_bg, LV_STATE_DEFAULT, LV_GRAD_DIR_HOR);
*/
/* Create and object with the gradient style on the object mask.
* The arc will be masked from the gradient*/
// lv_obj_t * bg = lv_obj_create(om, NULL);
bg = lv_img_create(om, NULL);
LV_IMG_DECLARE(pointer_bg);
lv_img_set_src(bg, &pointer_bg);
lv_obj_align(bg, NULL, LV_ALIGN_CENTER, 0, 0); //图片是mask的子对象,所以对齐中心即可
lv_obj_reset_style_list(bg, LV_OBJ_PART_MAIN);
// lv_obj_add_style(bg, LV_OBJ_PART_MAIN, &style_bg);
lv_obj_set_size(bg, MASK_WIDTH, MASK_HEIGHT);
}
void lv_ex_img_3(void)
{
//全黑背景
static lv_style_t style_bg;
lv_style_init(&style_bg);
lv_style_set_bg_opa(&style_bg, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_bg_color(&style_bg, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_add_style(lv_scr_act(), LV_OBJ_PART_MAIN, &style_bg);
//随指针动作的底图
arc_mask_test(180-45);
//表盘图
imgBg = lv_img_create(lv_scr_act(), NULL);
LV_IMG_DECLARE(pointer_bg_1);
lv_img_set_src(imgBg, &pointer_bg_1);
lv_obj_align(imgBg, NULL, LV_ALIGN_CENTER, 0, 0);
/*指针图*/
img = lv_img_create(lv_scr_act(), NULL);
//lv_img_set_src(img, &img_cogwheel_argb);
LV_IMG_DECLARE(pointer);
lv_img_set_src(img, &pointer);
lv_obj_align(img, NULL, LV_ALIGN_CENTER, 60, 44); //指针长150pt,旋转中心位于15pt处,所以对齐到中心还要偏移150/2-15=60pt
lv_img_set_pivot(img, 15, 15); //绕着图像相对于左上角的偏移来旋转
lv_img_set_angle(img, 1800-450);
//文本:
label1 = lv_label_create(lv_scr_act(), NULL);
//设置字体
static lv_style_t styleFont; //必须是静态的
lv_style_init(&styleFont);
lv_style_set_text_font(&styleFont, LV_STATE_DEFAULT, &lv_font_montserrat_30);
lv_obj_add_style(label1, LV_GAUGE_PART_MAIN, &styleFont);
lv_label_set_long_mode(label1, LV_LABEL_LONG_EXPAND); /*Break the long lines*/
lv_label_set_recolor(label1, true); /*Enable re-coloring by commands in the text*/
lv_label_set_align(label1, LV_LABEL_ALIGN_CENTER); /*Center aligned lines*/
lv_label_set_text_fmt(label1, “#ff0000 %d#”, 0);
lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, -15);
static uint32_t user_data = 10;
lv_task_create(my_task, 100, LV_TASK_PRIO_HIGH, &user_data);
//指针动画
/* lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, img);
//这个后播放
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_img_set_angle);
lv_anim_set_values(&a, 1800+1800+450, 1800-450); //因为该指针图像朝右,有个180度的起始值,表盘底部空出90度不用,对称的原因所以要加45度
lv_anim_set_time(&a, 5000);
//lv_anim_set_repeat_count(&a, 1);
lv_anim_set_playback_time(&a, 5000);
lv_anim_start(&a);
//这个先播放:
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_img_set_angle);
lv_anim_set_values(&a, 1800-450, 1800+1800+450); //因为该指针图像朝右,有个180度的起始值,表盘底部空出90度不用,对称的原因所以要加45度
lv_anim_set_time(&a, 5000);
lv_anim_set_playback_time(&a, 5000);
//lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
*/
//lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_img_set_zoom);
//lv_anim_set_values(&a, 128, 400);
//lv_anim_set_playback_time(&a, 1000);
//lv_anim_start(&a);
}
#endif