设置APP

本文说明设置应用的页面组织、配置入口和功能接入方式。

1. 参考代码

文件

作用

solution\framework\gui_fwk\setting_fwk\setting_fwk.c

管理设置页面入口、跳转和参数传递

2. 应用例程

场景

文件

调用接口

设置主页面

setting_main_gui.c

setting_get_fwk_list()、setting_main_add_info()、setting_main_create_item_cb()

3. 介绍

  • 「设置」本身是一款独立的系统内置应用 APP,完成设备全局参数配置、各应用个性化参数设置等功能,是系统级的配置管理类应用;

  • 某一些设置项与具体的应用APP相关,为了实现设置APP和其他应用APP的独立,Solution提供了「应用设置项」的功能。 应用可以通过 SETTING_REGISTER 宏完成设置项注册,从而实现在设置APP中实现对应用参数的设置;

  • 「应用设置项」是与特定应用绑定的配置入口,仅当对应应用存在时,设置项才会被注册并显示在系统设置菜单列表中。用户可通过点击设置项触发回调逻辑,实现应用配置页面的跳转与参数调整。

除应用设置项外,框架也提供可选的主题设置支持。该能力不影响设置APP的基础注册、跳转和配置管理流程,客户可根据产品需求选择是否启用;当前 Watch 示例已在设置APP中完成一套主题设置实现。

4. 注册设置项

通过 SETTING_REGISTER 宏完成设置项注册,该宏统一管理设置项的标识、排序、显示及交互逻辑,语法如下:

    SETTING_REGISTER(id, priority, name, thumb_img, callback)

参数说明:

参数名

类型

功能描述

id

字符串

设置菜单唯一标识 ID,框架通过该 ID 识别设置项,需保证全局唯一性

priority

无符号整数

设置项显示优先级,数值越小优先级越高,在设置菜单中排列越靠前

name

多语言字符串

设置项显示名称,用于菜单界面展示,支持多语言切换(如通过 app_get_strid 获取)

thumb_img

图片指针

设置项图标,用于菜单界面可视化展示,可通过 APP_GET_IMG_FROM_APP 获取应用内图片

callback

函数指针

点击回调函数,触发设置项对应的页面跳转或逻辑处理

5. 结构体说明

设置项的元数据与运行时状态通过以下两个结构体管理,分别对应注册描述与节点实例:

  1. 运行时节点结构体(setting_node_t) 用于存储设置项的运行时状态,由框架动态维护:

    typedef struct
    {
        char                    id[MAX_SETTING_NAME_LEN];   /**< 设置菜单id名称                             */
        char                    *title;                     /**< 设置项名字,字符串,框架调度该设置项时使用   */
        uint32_t                prio;                       /**< 设置菜单优先级,值越小,优先级越高         */
        const void              *thumbnail;                 /**< 设置菜单缩略图                             */
        setting_cb_t            cb;                         /**< 回调函数,点击菜单后页面跳转逻辑处理回调   */
        void                    *mod;                       /**< 动态模块指针                               */
        void                    *mem_ptr;                   /**< setting菜单全局指针                        */
        void                    *user_data;                 /**< setting菜单user data                       */
        rt_list_t               list;                       /**< 链表                                       */
        setting_built_type_t    built_type;                 /**< 设置菜单类型, 动态菜单还是内置菜单         */
    } setting_node_t;
  1. 注册描述结构体(setting_desc_t) 用于定义设置项的静态注册信息,作为注册时的参数载体:

    typedef struct
    {
        const char              *id_str;                    /**< 设置菜单id名称                             */
        const uint32_t          prio;                       /**< 设置菜单优先级,值越小,优先级越高         */
        setting_cb_t            cb;                         /**< 回调函数,点击菜单后页面跳转逻辑处理回调   */
        const void              *thumbnail;                 /**< 设置菜单缩略图                             */
        uint32_t                title;                      /**< 设置项名字,字符串,框架调度该设置项时使用   */
    } setting_desc_t;

6. 注册与开发流程

设置项的完整开发流程包含页面实现、回调绑定、设置项注册三个核心步骤,具体如下:

6.1 实现设置项对应的配置页面

配置页面需遵循应用页面生命周期规范,实现 on_start/on_resume/on_pause/on_stop 函数,完成页面创建、数据初始化、资源释放等逻辑。下面以AOD应用为例,在设置APP中增加AOD的设置项。

// 定义设置项页面数据结构
typedef struct {
    lv_obj_t *bg_parent;    // 页面背景容器
    lv_obj_t *slide_page;   // 滑动列表页面(示例控件)
} aod_setting_t;

static aod_setting_t *p_aod_setting = NULL;  // 全局页面指针
static app_aod_t *p_aod = NULL;              // 应用核心数据指针

/**
 * 页面初始化(仅调用一次)
 * 功能:创建页面背景容器,申请基础资源
 */
static void on_start(void)
{
    // 获取框架分配的全局内存
    p_aod_setting = (aod_setting_t *)APP_GET_PAGE_MEM_PTR;
    RT_ASSERT(p_aod_setting);  // 校验内存分配有效性

    // 创建全屏背景容器
    lv_obj_t *bg_parent = lv_obj_create(lv_scr_act());
    lv_obj_set_size(bg_parent, LV_HOR_RES_MAX, LV_VER_RES_MAX);
    lv_obj_set_style_bg_color(bg_parent, LV_COLOR_BLACK, LV_PART_MAIN);
    lv_obj_clear_flag(bg_parent, LV_OBJ_FLAG_SCROLLABLE);
    lv_obj_center(bg_parent);
    lv_obj_update_layout(bg_parent);

    p_aod_setting->bg_parent = bg_parent;
}

/**
 * 页面激活(每次显示时调用)
 * 功能:创建交互控件,刷新页面数据
 */
static void on_resume(void)
{
    // 获取应用核心数据(如AOD功能配置)
    p_aod = aod_info_get();

    // 创建具体配置控件(示例:AOD开关页面)
    aod_setting_create_onoff_page(p_aod_setting->bg_parent);
}

/**
 * 页面暂停(被切换至后台时调用)
 * 功能:暂停动态控件(如滑动列表),保存临时状态
 */
static void on_pause(void)
{
    if (p_aod_setting->slide_page) {
        lv_multlist_on_pause(p_aod_setting->slide_page);  // 暂停滑动列表交互
    }
}

/**
 * 页面销毁(退出时调用)
 * 功能:释放全局指针,避免悬空引用
 */
static void on_stop(void)
{
    p_aod_setting = NULL;
}

// 注册设置项对应的配置页面(绑定至"setting"应用下的"aod"子页面)
APP_PAGE_REGISTER("setting", "aod", sizeof(aod_setting_t));

6.2 实现设置项点击回调函数

回调函数用于响应菜单点击事件,实现从设置菜单到配置页面的跳转:

/**
 * AOD设置项点击回调
 * param:用户自定义参数(可选)
 * 返回值:0表示成功,非0表示失败
 */
static int aod_setting_cb(void *param)
{
    // 跳转至"setting"应用下的"aod"配置页面
    gui_app_run_subpage("setting", "aod", NULL);
    return 0;
}

6.3 注册设置项至系统菜单

通过 SETTING_REGISTER 宏将设置项添加到系统设置菜单,完成最终注册:

// 注册AOD设置项至系统菜单
SETTING_REGISTER(
    aod_setting,                          // 设置项唯一ID
    1,                                    // 优先级(1级,显示靠前)
    app_get_strid(key_aod_setting, "Aod setting"),  // 多语言显示名称
    APP_GET_IMG_FROM_APP(setting, img_screen_always_on),  // 设置项图标
    aod_setting_cb                        // 点击回调函数
);

具体例程参考solution\examples\watch\application\aod\aod_setting_gui.c。

7. 可选主题设置

主题设置是设置APP的可选外观能力,用于让产品在运行时切换页面色板。框架侧通过公共主题服务提供主题色板注册和读取接口,应用侧可以选择接入,也可以完全不使用该能力。

当前 Watch 示例在 solution\examples\watch\application\setting\setting_theme 下实现了主题设置页面。用户从设置主页面进入 Theme/Appearance 页面后,可选择不同主题;选中后会立即刷新设置应用内的页面背景、标题栏、列表卡片、选中态、开关和文字颜色。

文件

作用

solution\framework\service\srv_app\comm\app_theme.h

定义公共主题色板结构体,以及主题注册和读取接口。

setting_comm.c

维护 Watch 示例的当前主题、主题色板和通用样式接口。

setting_comm.h

定义 Watch 示例的主题 ID、色板类型和对外调用接口。

setting_theme_gui.c

创建 Watch 示例的主题选择页面,并处理主题点击切换。

Watch 示例当前内置 8 套主题:Black Flat、Amber Dusk、Teal Wave、Crimson Night、Army Green、Sky Blue、Neon Purple、Retro LCD Green。主题切换通过 setting_set_theme() 更新当前主题,再由 setting_apply_background_style()、setting_apply_title_style()、setting_apply_page_style()、setting_apply_list_card_style() 等接口统一刷新控件外观。

设置应用启动时可通过 app_theme_register() 将当前色板提供给公共主题服务。其他模块如果需要跟随主题色,可通过 app_theme_get_palette() 或 APP_THEME_COLOR_HEX(field, fallback) 读取当前主题色;如果产品不需要主题能力,则无需调用这些接口,也无需实现主题设置页面。

7.1 增加或删除主题

Watch 示例增加或删除一个主题时,通常只需要维护以下核心位置:

  1. setting_comm.h 中的 setting_theme_id_t:增加或删除主题枚举,并保持 SETTING_THEME_COUNT 位于末尾。

  2. setting_comm.c 中的 setting_theme_palettes:增加或删除对应主题色板,字段顺序需与 app_theme_palette_t 保持一致。

  3. setting_comm.c 中的 setting_get_theme_name():增加或删除对应显示名称。主题选择页面统一调用该公共接口,不需要再维护第二份页面内名称映射。

如需正式多语言显示,还需要在 solution/examples/watch/resource/langs/multi_language_table.xlsx 中增加或删除对应 key,并重新生成语言资源。

主题选择页面通过 setting_theme_create_page() 按 SETTING_THEME_COUNT 自动生成主题卡片,不需要为每个主题手写页面控件。主题点击后统一进入 setting_set_theme(),不需要为单个主题增加保存分支。

当前 Watch 示例会把选中的主题 ID 写入系统 NVM 内存镜像,并在启动或重新进入时恢复。写入使用 nvm_sys_update(setting_theme, theme, 0),不会立即调用 sys_nvm_flash_save(),仍沿用系统 sleep 等统一时机保存。NVM 字段 setting_theme 当前为 4 bit,可保存 0 到 15 的主题 ID;主题数量超过 16 个时,才需要同步扩大该字段位宽并调整 reserved。

代码目录下的补充说明可参考 solution\examples\watch\application\setting\setting_theme\readme.md。

8. 注意事项

  • 唯一性保证: id 参数需保证全局唯一,避免与其他设置项冲突导致框架调度异常。

  • 内存管理: 配置页面的全局内存由框架通过 APP_GET_PAGE_MEM_PTR 分配,其大小需与 APP_PAGE_REGISTER 中指定的 sizeof(页面结构体) 一致。

  • 优先级设计: 核心配置项(如 “显示设置”)建议设置较低优先级数值(如 1-5),次要配置项可设置较高数值(如 10+),确保菜单排序符合用户预期。

  • 多语言支持: name 参数需使用多语言接口(如 app_get_strid),避免硬编码字符串导致多语言适配问题。

  • 资源清理: on_stop 函数中需将全局指针置空,避免内存泄漏;页面控件无需手动删除,框架会自动清理。