lvgl 页面管理器

lv_scr_mgr

lvgl 界面管理器

适配 lvgl 8.3

  • 降低界面之间的耦合
  • 使用较小的内存,界面切换后会自动释放内存
  • 内存泄漏检测
    请添加图片描述

使用方法

  1. 在lv_scr_mgr_port.h 中创建一个枚举,用于界面ID
  2. 为每个界面创建一个页面管理器句柄
  3. 将界面句柄添加到 lv_scr_mgr_port.c 数组中
  4. 在 lv_init() 后,对页面管理器进行初始化 lv_scr_mgr_init(NULL);
  5. 使用 lv_scr_mgr_switch 设置初始根界面
  6. 使用 lv_scr_mgr_push lv_scr_mgr_pop 对界面进行操作

git地址

git地址
gitee

/*********************************CopyRight  ************************************* @file    lv_scr_mgr.c* @author  不咸不要钱* @date    2023-10-11 13:4:36* @brief   &#&*          *******************************************************************************//* Includes ------------------------------------------------------------------*/
#include "lvgl.h"
#include "lv_scr_mgr.h"
#if !LV_SCR_MGR_REG_ENABLE
#include "lv_scr_mgr_port.c"
#endiftypedef struct
{uint32_t               scr_cnt; void*                  param;lv_scr_mgr_handle_t    **handles;
#if LV_SCR_MGR_PRINTF_MEMuint32_t               *max_mem;
#endif
}scr_mgr_list_handle_t;static scr_mgr_list_handle_t     mgr_list;
static lv_scr_mgr_stack_node_t*      mgr_stack_top = NULL;
static lv_scr_mgr_stack_node_t*      mgr_stack_root = NULL;static lv_scr_mgr_handle_t* find_handle_by_id(uint32_t id)
{for (int i = 0; i < mgr_list.scr_cnt; i++){if (mgr_list.handles[i]->scr_id == id){return mgr_list.handles[i];}}return NULL;
}
#if LV_SCR_MGR_PRINTF_MEM
static uint32_t* find_mem_addr_by_id(uint32_t id)
{for (int i = 0; i < mgr_list.scr_cnt; i++){if (mgr_list.handles[i]->scr_id == id){return &mgr_list.max_mem[i];}}return NULL;
}static void mem_max_printf(uint32_t id)
{static uint32_t mem_max = 0;lv_mem_monitor_t mon;lv_mem_monitor(&mon);if (mon.total_size - mon.free_size > mem_max){mem_max = mon.total_size - mon.free_size;LV_LOG_USER("used: %d (%d %%), frag: %d %%, biggest free: %d\n", mem_max,mon.used_pct,mon.frag_pct,(int)mon.free_biggest_size);}/* 当前界面最大使用内存 */uint32_t* page_max_mem = find_mem_addr_by_id(id);if (mon.total_size - mon.free_size > *page_max_mem){*page_max_mem = mon.total_size - mon.free_size;LV_LOG_USER("page id %d, used: %d (%d %%), frag: %d %%, biggest free: %d\n", id, *page_max_mem,mon.used_pct,mon.frag_pct,(int)mon.free_biggest_size);}
}static void anim_mem_max_printf(lv_event_t* e)
{lv_event_code_t event_code = lv_event_get_code(e);if (event_code == LV_EVENT_SCREEN_LOADED){mem_max_printf((uint32_t)lv_event_get_user_data(e));}
}
#endifstatic void scr_mgr_stack_free(void)
{lv_scr_mgr_stack_node_t* stack_node = NULL;/* 释放界面栈 */while (NULL != mgr_stack_top){stack_node = mgr_stack_top->prev;if(mgr_stack_top->handle->scr_destroy)mgr_stack_top->handle->scr_destroy();lv_mem_free((void*)mgr_stack_top);mgr_stack_top = stack_node;}mgr_stack_root = NULL;
}/*** @brief 入栈* @param tag 要入栈的句柄* @return 栈顶句柄
*/
static lv_scr_mgr_stack_node_t* scr_mgr_stack_push(lv_scr_mgr_handle_t* tag)
{lv_scr_mgr_stack_node_t* stack_node = NULL;stack_node = lv_mem_alloc(sizeof(lv_scr_mgr_stack_node_t));LV_ASSERT_MALLOC(stack_node);stack_node->handle = tag;stack_node->next = NULL;if (stack_node->handle->scr_first_create){stack_node->handle->scr_first_create();}if (tag->scr_create){stack_node->scr = tag->scr_create(stack_node->handle->scr_id, mgr_list.param);}else{LV_LOG_ERROR("no create fun!");}if (NULL == mgr_stack_top){stack_node->prev = NULL;mgr_stack_root = stack_node;}else{stack_node->prev = mgr_stack_top;mgr_stack_top->next = stack_node;}mgr_stack_top = stack_node;return stack_node;
}static int32_t scr_mgr_stack_pop(int32_t n)
{lv_scr_mgr_stack_node_t* stack_node = NULL;int32_t i = n;if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev)){return 0;}while (i){if ((NULL == mgr_stack_top) || (NULL == mgr_stack_top->prev)){break;}stack_node = mgr_stack_top->prev;if (mgr_stack_top->handle->scr_destroy){mgr_stack_top->handle->scr_destroy();}lv_mem_free((void*)mgr_stack_top);mgr_stack_top = stack_node;i--;}if (NULL != mgr_stack_top->handle->scr_create){mgr_stack_top->scr = mgr_stack_top->handle->scr_create(mgr_stack_top->handle->scr_id, mgr_list.param);}else{LV_LOG_ERROR("no create fun!");}if (i){LV_LOG_WARN("stack pop %d, but stack is %d", n, n-i);}return n - i;
}/*** @brief 切换界面* @param cur_scr 当前界面* @param stack_node 目标界面句柄* @param anim 切换界面动画开关*             关闭界面切换动画,切换界面时会先创建一个新的空界面,切换到空界面后,*             删除之前的界面,然后再创建切换到新界面,最后再删除中间界面。会节省内存。*             关闭界面切换动画,切换界面时直接创建新界面,然后再用动画切换到新界面。** @return true
*/
bool scr_mgr_switch(lv_obj_t* cur_scr, lv_scr_mgr_stack_node_t* stack_node, bool anim)
{lv_scr_load_anim_t load_anim = LV_SCR_MGR_LOAD_ANIM_DEFAULT;lv_obj_t* tmp_scr = NULL;if (anim){if ((stack_node->handle->anim_type != LV_SCR_LOAD_ANIM_NONE) && (LV_SCR_LOAD_ANIM_OUT_BOTTOM >= stack_node->handle->anim_type)){load_anim = stack_node->handle->anim_type;}#if LV_SCR_MGR_PRINTF_MEMlv_obj_add_event_cb(stack_node->scr, anim_mem_max_printf, LV_EVENT_SCREEN_LOADED, stack_node->handle->scr_id);
#endiflv_scr_load_anim(stack_node->scr, load_anim, LV_SCR_MGR_LOAD_ANIM_TIME, LV_SCR_MGR_LOAD_ANIM_DELAY, true);}else{if (NULL != cur_scr){tmp_scr = lv_obj_create(NULL);lv_scr_load(tmp_scr);lv_obj_del(cur_scr);cur_scr = NULL;}lv_scr_load(stack_node->scr);#if LV_SCR_MGR_PRINTF_MEMmem_max_printf(stack_node->handle->scr_id);
#endifif (NULL != tmp_scr){lv_obj_del(tmp_scr);}}return true;
}/*** @brief 初始化界面管理器* @param param 创建界面时的参数* @return 
*/
bool lv_scr_mgr_init(void* param)
{mgr_list.param = param;
#if LV_SCR_MGR_REG_ENABLE#elsemgr_list.scr_cnt = sizeof(scr_mgr_handles) / sizeof(scr_mgr_handles[0]);mgr_list.handles  = scr_mgr_handles;
#endif    if (0 == mgr_list.scr_cnt){LV_LOG_ERROR("no screen!");return false;}#if LV_SCR_MGR_PRINTF_MEMmgr_list.max_mem = lv_mem_alloc(mgr_list.scr_cnt * sizeof(uint32_t*));LV_ASSERT(mgr_list.max_mem);memset(mgr_list.max_mem, 0, mgr_list.scr_cnt * sizeof(uint32_t*));
#endifreturn true;
}void lv_scr_mgr_deinit(void)
{mgr_list.param = NULL;
#if LV_SCR_MGR_PRINTF_MEMlv_mem_free(mgr_list.max_mem);
#endifscr_mgr_stack_free();
}void lv_scr_mgr_param_set(void* param)
{mgr_list.param = param;
}void* lv_scr_mgr_param_get(void)
{return mgr_list.param;
}/*** @brief 设置根界面* @param id 根界面序号* @param anim 动画开关* @return 
*/
bool lv_scr_mgr_switch(uint32_t id, bool anim)
{lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id);lv_scr_mgr_handle_t* cur_handle = NULL;lv_scr_mgr_stack_node_t* stack_node = NULL;lv_obj_t* cur_scr = NULL;if (NULL == tag_handle){LV_LOG_ERROR("no screen, id %d", id);return false;}if (NULL != mgr_stack_top){/* 栈内有界面 */cur_handle = mgr_stack_top->handle;cur_scr = mgr_stack_top->scr;}else{cur_scr = lv_scr_act();}scr_mgr_stack_free();if ((NULL == cur_handle) || (tag_handle->scr_id == cur_handle->scr_id)){/* 没有界面切换,不使用动画效果 */anim = false;}stack_node = scr_mgr_stack_push(tag_handle);return scr_mgr_switch(cur_scr, stack_node, anim);
}/*** @brief 入栈一个新的界面* @param id * @param anim * @return 
*/
bool lv_scr_mgr_push(uint32_t id, bool anim)
{lv_scr_mgr_handle_t* tag_handle = find_handle_by_id(id);lv_scr_mgr_stack_node_t* stack_node = NULL;lv_obj_t* cur_scr = NULL;if (NULL == tag_handle){LV_LOG_ERROR("no screen, id %d", id);return false;}if ((NULL == mgr_stack_top) || (NULL == mgr_stack_root)){LV_LOG_ERROR("no root screen, please use lv_scr_mgr_switch create root screen");return false;}cur_scr = mgr_stack_top->scr;stack_node = scr_mgr_stack_push(tag_handle);return scr_mgr_switch(cur_scr, stack_node, anim);
}/*** @brief 出栈n个界面* @param n 如果栈内界面没有n个,则返回根界面* @param anim * @return 
*/
bool lv_scr_mgr_popn(uint32_t n, bool anim)
{lv_obj_t* cur_scr = NULL;if ((mgr_stack_top == NULL) || (mgr_stack_top->prev == NULL)){return false;}cur_scr = mgr_stack_top->scr;scr_mgr_stack_pop(n);return scr_mgr_switch(cur_scr, mgr_stack_top, anim);
}/*** @brief 出栈一个界面* @param anim * @return 
*/
bool lv_scr_mgr_pop(bool anim)
{return lv_scr_mgr_popn(1, anim);
}/*** @brief 退回到根界面* @param anim * @return 
*/
bool lv_scr_mgr_pop_root(bool anim)
{lv_scr_mgr_stack_node_t* stack_node = NULL;lv_scr_mgr_stack_node_t* stack_top = NULL;uint32_t cnt = 0;if (NULL == mgr_stack_root || NULL == mgr_stack_top){return false;}stack_top = mgr_stack_top;while (stack_top != NULL){cnt++;stack_node = stack_top->prev;stack_top = stack_node;}return lv_scr_mgr_popn(cnt-1, anim);
}/*** @brief 获取当前界面id* @param  * @return 
*/
int32_t lv_scr_mgr_get_cur_id(void)
{if (NULL != mgr_stack_top && NULL != mgr_stack_top->handle){return mgr_stack_top->handle->scr_id;}else{return -1;}
}/*** @brief 获取根界面id* @param* @return
*/
int32_t lv_scr_mgr_get_root_id(void)
{if (NULL != mgr_stack_root && NULL != mgr_stack_root->handle){return mgr_stack_root->handle->scr_id;}else{return -1;}
}
/************************ (C) COPYRIGHT ***********END OF FILE*****************/
/*********************************CopyRight  ************************************* @file    lv_scr_mgr.h* @author  不咸不要钱* @date    2023-10-11 9:31:49* @brief   &#&*          *******************************************************************************/
#ifndef _LV_SCR_MGR_H_
#define _LV_SCR_MGR_H_/* Includes ------------------------------------------------------------------*/
#include "stdint.h"
#include "lvgl.h"#ifdef __cplusplus
extern "C" {
#endif/*!<  界面切换动画默认值*/
#define LV_SCR_MGR_LOAD_ANIM_DEFAULT   LV_SCR_LOAD_ANIM_MOVE_LEFT
#define LV_SCR_MGR_LOAD_ANIM_TIME      500
#define LV_SCR_MGR_LOAD_ANIM_DELAY     0/*!< 内存泄漏检测 */
#define LV_SCR_MGR_PRINTF_MEM          1   #define LV_SCR_MGR_REG_ENABLE          0#if LV_SCR_MGR_REG_ENABLE#else#endiftypedef struct
{uint32_t scr_id;                       /*!< id */lv_scr_load_anim_t      anim_type;     /*!< 切换动画类型 如果为空,则使用 LV_SCR_MGR_LOAD_ANIM_DEFAULT */void (*scr_first_create)(void);        /*!< lv_scr_mgr_switch  lv_scr_mgr_push 函数会调用该创建函数 pop则不会调用 可以方便实现pop记住焦点 而push使用默认焦点 */lv_obj_t* (*scr_create) (const uint32_t id, void* param); /*!< 创建界面,创建界面时不要使用 lv_scr_mgr_xxx 函数 */void (*scr_destroy)(void);             /*!< 删除界面的回调函数,一般用于删除如 lv_timer 等不会随界面自动删除的资源 */
}lv_scr_mgr_handle_t;typedef struct _lv_scr_mgr_stack_node_t
{lv_scr_mgr_handle_t* handle;lv_obj_t* scr;struct _lv_scr_mgr_stack_node_t* prev;struct _lv_scr_mgr_stack_node_t* next;
}lv_scr_mgr_stack_node_t;bool lv_scr_mgr_init(void* param);
void lv_scr_mgr_deinit(void);
void lv_scr_mgr_param_set(void* param);
void* lv_scr_mgr_param_get(void);bool lv_scr_mgr_switch(uint32_t id, bool anim);
bool lv_scr_mgr_push(uint32_t id, bool anim);
bool lv_scr_mgr_popn(uint32_t n, bool anim);
bool lv_scr_mgr_pop(bool anim);
bool lv_scr_mgr_pop_root(bool anim);
int32_t lv_scr_mgr_get_cur_id(void);
int32_t lv_scr_mgr_get_root_id(void);
#ifdef __cplusplus
}
#endif#endif /* _LV_SCR_MGR_H_ *//************************ (C) COPYRIGHT *****END OF FILE*****************/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/138706.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

55 零钱兑换

零钱兑换 题解1 DP另一种解法(更好记) 题解2 递归 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额&#xff0c;返回…

【vr】【unity】白马VR课堂系列-VR开发核心基础05-主体设置-手柄对象的引入和设置

【视频教学】 【白马VR课堂系列-VR开发核心基础05-主体设置-手柄对象的引入和设置】 https://www.bilibili.com/video/BV19D4y1N73i/?share_source=copy_web&vd_source=7f5c96f5a58b7542fc6b467a9824b04e 【内容】 上一节引入了XR Origin并进行了初步设置,运行测试时V…

通达OA 2016网络智能办公系统 handle.php SQL注入漏洞

一、漏洞描述 北京通达信科科技有限公司通达OA2016网络智能办公系统 handle.php 存在sql注入漏洞&#xff0c;攻击者可利用此漏洞获取数据库管理员权限&#xff0c;查询数据、获取系统信息&#xff0c;威胁企业单位数据安全。 二、网络空间搜索引擎查询 fofa查询 app"T…

STM32成熟变频逆变器方案

该方案是一款成熟的变频逆变器的方案&#xff0c;主要是把电源从直流到3相交流的转换&#xff0c;包含变频控制板&#xff0c;逆变主板&#xff0c;IO板&#xff0c;变频控制板主控是STM32F103VET6&#xff0c;配套软件。每一块板子都是原理图和PCB一一对应&#xff0c;并且配套…

element ui 下拉框 选择月份和天数

一、背景 目前做的管理系统项目&#xff0c;期望实现功能为&#xff1a;设置出账周期和出账日&#xff0c;考虑使用element ui下拉框实现功能 二、所用技术 vue2element ui 三、实现效果 四、具体代码 <template><popup-frame :title"批量设置出账日" …

Linux性能优化--性能工具:磁盘I/O

6.0 概述 本章介绍的性能工具能帮助你评估磁盘I/O子系统的使用情况。这些工具可以展示哪些磁盘或分区已被使用&#xff0c;每个磁盘处理了多少I/O,发给这些磁盘的I/O请求要等多久才被处理。 阅读本章后&#xff0c;你将能够&#xff1a; 确定系统内磁盘I/O的总量和类型(读/写…

阿里云2023年双十一优惠活动整理

随着双十一的临近&#xff0c;阿里云也为大家准备了一系列优惠活动。作为国内知名的云服务提供商&#xff0c;阿里云在双十一期间推出了多种优惠政策和福利&#xff0c;让用户在享受优质云服务的同时&#xff0c;也能节省一些费用。本文将对阿里云双十一优惠活动进行详细整理&a…

汽车安全的未来:毫米波雷达在碰撞避免系统中的角色

随着科技的飞速发展&#xff0c;汽车安全系统变得愈加智能化&#xff0c;而毫米波雷达技术正是这一领域的亮点之一。本文将深入探讨毫米波雷达在汽车碰撞避免系统中的关键角色&#xff0c;以及其对未来汽车安全的影响。 随着城市交通的拥堵和驾驶环境的变化&#xff0c;汽车安全…

Java idea查看自定义注解的调用地方

Java idea查看自定义注解的调用地方

手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (2)

上一篇文章中: 手撕ch7/pose_estimation_3d2d&#xff08;1&#xff09;&#xff0c;我们调用了epnp的方法进行位姿估计&#xff0c;这里我们使用非线性优化的方法来求解位姿&#xff0c;使用g2o进行BA优化 首先介绍g2o&#xff1a;可参考&#xff1a;g2o详细介绍 1.构建g2o图…

MySQLJDBC入门与SQL注入

MySQL-JDBC入门与SQL注入 一.JDBC概述 1.JDBC 在Java语言中提供对数据库访问的支持Sun公司于1996年提供了一套访问数据库的标准Java类库JDBCJDBC的全称是Java数据库连接(Java Database Connectivity)它是一套用于执行 SQL语句的Java API应用程序可通过这套API连接到关系数据…

“Flex弹性布局、轮播图mock遍历数据和首页布局解析与实践“

目录 引言1. Flex弹性布局介绍及使用什么是Flex弹性布局&#xff1f;Flex容器与Flex项目Flex属性详解 2. 轮播图mock遍历数据简述轮播图的作用和意义处理mock数据的重要性使用Mock模拟数据遍历 3. 首页布局总结 引言 在现代网页开发中&#xff0c;灵活性和响应式布局是至关重要…