LVGL 亮度调节实例

概述

平台炬芯,使用LVGL渲染UI界面,实现人机交互。本实例基于模拟器运行,可供参考。

比较传统写法,还有优化的空间。

1、Visual Studio 26版本

2、代码

cpp 复制代码
/*
 * Copyright (c) 2020 Actions Technology Co., Ltd
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file brightness_set_view.c
 */

#include <os_common_api.h>
#include <app_ui.h>
#include <view_stack.h>

/* picture idx */
enum {
	IDX_PIC_BS_BRIGHTNESS_DOWN_BTN = 0,
	IDX_PIC_BS_BRIGHTNESS_UP_BTN,
	IDX_PIC_BS_COUNT,
};

/* picture */
const static uint32_t _pic_ids[] = {
	PIC_BS_BRIGHTNESS_DOWN_BTN, PIC_BS_BRIGHTNESS_UP_BTN,
};

/* group picture idx */
enum {
	IDX_PIC_BS_BRIGHTNESS_SLIDER_BG = 0,
	IDX_PIC_BS_BRIGHTNESS_SLIDER_ICON,
	IDX_PIC_BS_GROUP_COUNT,
};

/* group picture */
const static uint32_t _pic_group_ids[] = {
	PIC_BS_BRIGHTNESS_SLIDER_BG, PIC_BS_BRIGHTNESS_SLIDER_ICON,
};

typedef struct brightness_set_view_data {
	lv_obj_t *scr;
	lv_obj_t *main_obj;
	/* lvgl resource */
	lvgl_res_scene_t res_scene;	 //场景
	lvgl_res_group_t res_group;  //资源组

	lv_img_dsc_t img_dsc[IDX_PIC_BS_COUNT];
	lv_img_dsc_t img_group_dsc[IDX_PIC_BS_GROUP_COUNT];

	lv_font_t font;
	
	/* user data */
	lv_obj_t *bright_down_btn;
	lv_obj_t *bright_up_btn;
	lv_obj_t *bright_slider;        // 滑动条主体
	lv_obj_t *bright_speaker_icon;  // 保存亮度图标引用
	int current_brightness;      // 新增:保存当前亮度值,用于联动
} brightness_set_view_data_t;

/* 滑动条值变化回调:同步当前亮度值(可选:可在此添加系统亮度设置逻辑) */
static void bright_slider_change_cb(lv_event_t *e)
{
	brightness_set_view_data_t *data = lv_event_get_user_data(e);
	if (!data || !data->bright_slider) return;

	// 获取滑动条当前值,更新到data中
	data->current_brightness = lv_slider_get_value(data->bright_slider);
	SYS_LOG_INF("current_brightness: %d", data->current_brightness);

	// 【可选】如果需要同步到系统亮度,添加这里:
	// set_brightness(data->current_brightness);
}

/* 亮度- 按键回调:控制滑动条值减少 */
static void bright_down_btn_cb(lv_event_t *e)
{
	brightness_set_view_data_t *data = lv_event_get_user_data(e);
	if (!data || !data->bright_slider) return;

	// 从滑动条获取当前值,减少5(步长可调整)
	int bright = lv_slider_get_value(data->bright_slider);
	if (bright > 0) {
		data->current_brightness = (bright - 5) < 0 ? 0 : (bright - 5); // 同步到data->current_brightness
		lv_slider_set_value(data->bright_slider, data->current_brightness, LV_ANIM_ON); // 带动画更新滑动条
		
		SYS_LOG_INF("bright_down_btn: %d", data->current_brightness);

		// 同步到系统亮度
		// set_brightness(data->current_brightness);
	}
}

/* 亮度+ 按键回调:控制滑动条值增加 */
static void bright_up_btn_cb(lv_event_t *e)
{
	brightness_set_view_data_t *data = lv_event_get_user_data(e);
	if (!data || !data->bright_slider) return;

	// 从滑动条获取当前值,增加5(步长可调整)
	int bright = lv_slider_get_value(data->bright_slider);
	if (bright < 100) {
		data->current_brightness = (bright + 5) > 100 ? 100 : (bright + 5); // 同步到data->current_brightness
		lv_slider_set_value(data->bright_slider, data->current_brightness, LV_ANIM_ON); // 带动画更新滑动条

		SYS_LOG_INF("bright_up_btn: %d", data->current_brightness);

		// 【可选】同步到系统亮度
		// os_audio_set_brightness(data->current_brightness);
	}
}

static int _brightness_set_view_preload(view_data_t *view_data)
{
	return lvgl_res_preload_scene_compact(SCENE_BRIGHENESS_SET_VIEW, NULL, 0, lvgl_res_scene_preload_default_cb_for_view, 
			(void *)SANAG_S7S_BRIGHENESS_SET_VIEW,
			SANAG_STY_FILE, SANAG_RES_FILE, SANAG_STR_FILE);
}

static int _brightness_set_view_load_resource(view_data_t *view_data)
{
	int ret;

	// alloc data
	brightness_set_view_data_t *data = app_mem_malloc(sizeof(*data));
	if (!data) {
		return -ENOMEM;
	}
	view_data->user_data = data;
	memset(data, 0, sizeof(*data));

	// 初始化默认亮度(比如50)
	data->current_brightness = 50;

	/* scene */
	ret = lvgl_res_load_scene(SCENE_BRIGHENESS_SET_VIEW, &data->res_scene,
			SANAG_STY_FILE, SANAG_RES_FILE, SANAG_STR_FILE);
	SYS_LOG_INF("load scene ret=%d", ret);		
	if (ret < 0) {
		SYS_LOG_ERR("SCENE_BRIGHENESS_SET_VIEW not found");
		return -ENOENT;
	}

	/* load picture from scene */
	ret = lvgl_res_load_pictures_from_scene(&data->res_scene, _pic_ids, data->img_dsc, NULL, IDX_PIC_BS_COUNT);
	SYS_LOG_INF("load picture from scene ret=%d", ret);
	if (ret < 0) {
		SYS_LOG_ERR("load picture from scene failed");
		goto out_exit;
	}

	/* load group from scene */
	ret = lvgl_res_load_group_from_scene(&data->res_scene, RES_BS_BRIGHTNESS_SLIDER, &data->res_group);
	SYS_LOG_INF("load group from scene ret=%d", ret);
	if (ret < 0) {
		SYS_LOG_ERR("load group from scene failed");
		goto out_exit;
	}
	
	/* load pictures from group */
	ret = lvgl_res_load_pictures_from_group(&data->res_group, _pic_group_ids, data->img_group_dsc, NULL, IDX_PIC_BS_GROUP_COUNT);
	SYS_LOG_INF("load pictures from group ret=%d", ret);
	if (ret < 0) {
		SYS_LOG_ERR("load pictures from group failed");
		goto out_exit;
	}

	// font
	ret = LVGL_FONT_OPEN_DEFAULT(&data->font, DEF_FONT_SIZE_NORMAL);
	SYS_LOG_INF("open_font ret=%d", ret);
	if (ret < 0) {
		goto out_exit;
	}

	return 0;

out_exit:
	_brightness_set_view_unload_resource(view_data);
	SYS_LOG_ERR("load resource failed, exit");
	return ret;
}

static int _brightness_set_view_unload_resource(view_data_t *view_data)
{
	brightness_set_view_data_t *data = view_data->user_data;

	if (data) {
		lvgl_res_unload_scene(&data->res_scene);
		/* unload group */
		lvgl_res_unload_group(&data->res_group);
		/* unload picture */
		lvgl_res_unload_pictures(data->img_dsc, IDX_PIC_BS_COUNT);
		/* unload group picture */
		lvgl_res_unload_pictures(data->img_group_dsc, IDX_PIC_BS_GROUP_COUNT);
		/* close font */
		LVGL_FONT_CLOSE(&data->font);

		// 只删父容器,子控件自动销毁,杜绝重复删除崩溃
		if (data->main_obj != NULL && lv_obj_is_valid(data->main_obj)) {
			lv_obj_clean(data->main_obj);
			data->main_obj = NULL;
		}
		data->bright_down_btn = NULL;
		data->bright_up_btn = NULL;
		data->bright_slider = NULL;
		data->bright_speaker_icon = NULL;
		data->scr = NULL;
		/*
		if (data->scr != NULL && lv_obj_is_valid(data->scr)) {
			lv_obj_clean(data->scr);
			data->scr = NULL;
		}
		if (data->bright_down_btn != NULL && lv_obj_is_valid(data->bright_down_btn)) {
			lv_obj_clean(data->bright_down_btn);
			data->bright_down_btn = NULL;
		}
		if (data->bright_up_btn != NULL && lv_obj_is_valid(data->bright_up_btn)) {
			lv_obj_clean(data->bright_up_btn);
			data->bright_up_btn = NULL;
		}
		if (data->bright_slider != NULL && lv_obj_is_valid(data->bright_slider)) {
			lv_obj_clean(data->bright_slider);
			data->bright_slider = NULL;
		}	
		if (data->bright_speaker_icon != NULL && lv_obj_is_valid(data->bright_speaker_icon)) {
			lv_obj_clean(data->bright_speaker_icon);
			data->bright_speaker_icon = NULL;
		}*/

		// free data
		app_mem_free(data);
		view_data->user_data = NULL;

		SYS_LOG_INF("ok\n");
	} else {
		lvgl_res_preload_cancel_scene(SCENE_BRIGHENESS_SET_VIEW);
	}

	lvgl_res_unload_scene_compact(SCENE_BRIGHENESS_SET_VIEW);
	return 0;
}

static int _brightness_set_view_layout(view_data_t *view_data)
{
    brightness_set_view_data_t *data = (brightness_set_view_data_t *)view_data->user_data;
    data->scr = lv_disp_get_scr_act(view_data->display);

    data->main_obj = lv_obj_create(data->scr);
    if (!data->main_obj) {
        SYS_LOG_ERR("create main obj failed");
        goto fail_exit;
    }
    lv_obj_set_size(data->main_obj, DEF_UI_VIEW_WIDTH, DEF_UI_VIEW_HEIGHT);

    // 亮度减按钮
    data->bright_down_btn = lv_img_create(data->main_obj);
    lv_img_set_src(data->bright_down_btn, &data->img_dsc[IDX_PIC_BS_BRIGHTNESS_DOWN_BTN]);
    lv_obj_set_pos(data->bright_down_btn, 32, 214);
    lv_obj_add_flag(data->bright_down_btn, LV_OBJ_FLAG_CLICKABLE);
    lv_obj_set_user_data(data->bright_down_btn, data);
    lv_obj_add_event_cb(data->bright_down_btn, bright_down_btn_cb, LV_EVENT_CLICKED, data);

    // 亮度加按钮
    data->bright_up_btn = lv_img_create(data->main_obj);
    lv_img_set_src(data->bright_up_btn, &data->img_dsc[IDX_PIC_BS_BRIGHTNESS_UP_BTN]);
    lv_obj_set_pos(data->bright_up_btn, 298, 214);
    lv_obj_add_flag(data->bright_up_btn, LV_OBJ_FLAG_CLICKABLE);
    lv_obj_set_user_data(data->bright_up_btn, data);
    lv_obj_add_event_cb(data->bright_up_btn, bright_up_btn_cb, LV_EVENT_CLICKED, data);

    // 1. 滑动条背景图片(最底层,保留原图)
    lv_obj_t *bright_slider_bg = lv_img_create(data->main_obj);
    lv_img_set_src(bright_slider_bg, &data->img_group_dsc[IDX_PIC_BS_BRIGHTNESS_SLIDER_BG]);
    lv_obj_set_pos(bright_slider_bg, 30, 120);

    // 2. 创建滑动条(覆盖在背景图上,尺寸匹配)
    lv_obj_t *slider = lv_slider_create(data->main_obj);
    lv_obj_set_size(slider, 320, 80);
    lv_obj_set_pos(slider, 30, 120);
    lv_slider_set_range(slider, 0, 100);
    lv_slider_set_value(slider, data->current_brightness, LV_ANIM_OFF); // 初始化到默认亮度

    // 滑动条样式优化(匹配设计图)
    lv_obj_set_style_bg_opa(slider, LV_OPA_0, LV_PART_MAIN);        // 隐藏默认底框
    lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_INDICATOR); // 选中区域白色
    lv_obj_set_style_bg_opa(slider, LV_OPA_100, LV_PART_INDICATOR);  // 选中区域不透明
    lv_obj_set_style_radius(slider, 40, LV_PART_INDICATOR);         // 半圆角(80高→40圆角)
    lv_obj_set_style_pad_all(slider, 0, LV_PART_INDICATOR);         // 无内边距
    lv_obj_set_style_bg_color(slider, lv_color_hex(0x333333), LV_PART_MAIN); // 未选中区域深灰
    lv_obj_set_style_bg_opa(slider, LV_OPA_80, LV_PART_MAIN);       // 未选中区域半透
    lv_obj_set_style_radius(slider, 40, LV_PART_MAIN);              // 整体圆角
    lv_obj_set_style_border_width(slider, 0, LV_PART_MAIN);         // 无边框
    lv_obj_set_style_bg_opa(slider, LV_OPA_0, LV_PART_KNOB);        // 隐藏默认滑块
    lv_obj_set_style_size(slider, 0, LV_PART_KNOB);                 // 滑块尺寸为0

    // 绑定滑动条值变化事件(拖动滑动条同步亮度值)
    lv_obj_set_user_data(slider, data);
    lv_obj_add_event_cb(slider, bright_slider_change_cb, LV_EVENT_VALUE_CHANGED, data);

    // 3. 亮度图标(创建为main_obj的子对象,确保置顶不遮挡)
    data->bright_speaker_icon = lv_img_create(data->main_obj);
    lv_img_set_src(data->bright_speaker_icon, &data->img_group_dsc[IDX_PIC_BS_BRIGHTNESS_SLIDER_ICON]);
    lv_obj_align_to(data->bright_speaker_icon, bright_slider_bg, LV_ALIGN_LEFT_MID, 30, 0); // 固定位置
    lv_obj_move_foreground(data->bright_speaker_icon); // 强制置顶(核心:解决遮挡)

    // 保存滑动条引用
    data->bright_slider = slider;

    return 0;

fail_exit:
    _brightness_set_view_unload_resource(view_data);
    return -ENOMEM;
}

static int _brightness_set_view_paint(view_data_t *view_data)
{
	return 0;
}

static int _brightness_set_view_key(view_data_t *view_data)
{
	ui_key_msg_data_t *key_data = (ui_key_msg_data_t *)view_data;

	if (KEY_VALUE(key_data->event) == KEY_GESTURE_RIGHT) {
		view_stack_pop();
		key_data->done = true;
	}

	return 0;
}

int _brightness_set_view_handler(uint16_t view_id, uint8_t msg_id, void *msg_data)
{
	view_data_t *view_data = msg_data;

	SYS_LOG_INF("_brightness_set_view_handler: view_id=%d, msg_id=%d", view_id, msg_id);

	switch (msg_id) {
	case MSG_VIEW_PRELOAD:
		return _brightness_set_view_preload(view_data);
	case MSG_VIEW_LAYOUT:
		if (_brightness_set_view_load_resource(view_data)) return -ENOENT;
		return _brightness_set_view_layout(view_data);
	case MSG_VIEW_DELETE:
		return _brightness_set_view_unload_resource(view_data);
	case MSG_VIEW_PAINT:
		return _brightness_set_view_paint(view_data);
	case MSG_VIEW_KEY:
		return _brightness_set_view_key(view_data);	
	default:
		return 0;
	}
}

VIEW_DEFINE(brightness_set, _brightness_set_view_handler, NULL, NULL,
			SANAG_S7S_BRIGHENESS_SET_VIEW, NORMAL_ORDER, UI_VIEW_LVGL,
			DEF_UI_VIEW_WIDTH, DEF_UI_VIEW_HEIGHT);

3、运行结果

相关推荐
山木嵌入式2 小时前
FreeRTOS从入门到进阶:核心概念与调度原理全解析
stm32·操作系统·嵌入式·freertos·rtos
lularible2 小时前
PTP协议精讲(4.5):编译运行与测试
网络·网络协议·开源·嵌入式·ptp
FreakStudio11 小时前
硬件版【Cursor】?aily blockly IDE尝鲜封神,实战硬伤尽显
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
青天喵喵19 小时前
Linux WiFi 架构解析:连接流程(基础篇二)
linux·运维·架构·嵌入式·wi-fi·sta·ap
山木嵌入式1 天前
同步通信与异步通信(UART/USART):定义、原理、场景全解析
串口·嵌入式·uart·通信
凉、介1 天前
ARM GICv3 学习笔记(一)
arm开发·笔记·学习·嵌入式
星恒讯工业路由器1 天前
星恒讯4G工业级无线数传模组选型指南:接口、环境适配与典型应用场景
arm开发·嵌入式·无线通信·4g模组
济6171 天前
FreeRTOS看门狗任务设计---软件看门狗 + 硬件 IWDG 双保险实现
嵌入式·freertos
Hello_Embed2 天前
libmodbus 移植到 STM32H5
笔记·stm32·单片机·嵌入式硬件·嵌入式·ai编程