KDocs 研发资料库
  • 手表穿戴技术应用文档入口汇总
  • JL707N穿戴客述问题FAQ
  • 彩屏仓 硬件开发指南 与 量产作业流程规范
  • 彩屏仓 AC98N和JL701烧录升级注意事项
  • JL707 硬件开发资料
  • JL707 手表硬件设计注意事项 总结
  • 穿戴生产烧录OTA和key文件添加使用说明
  • JL707N-入门到进阶开发指导文档
  • 彩屏仓982相关
  • 彩屏仓耳机介绍
  • 杰理701_707双屏demo介绍
  • 707电子吧唧开发资料
  • GPIO相关
  • UART串口相关
  • SPI相关
  • nandflash相关
  • norflash相关
  • IIC相关
  • PWM相关
  • SD卡相关
  • 定时器TIMER
  • 文件系统接口设计说明文档
  • 音视频录像开发流程
  • rdec编码器
  • 穿戴功耗数据标准
  • 手表蓝牙开发文档
  • 701蓝牙PAN联网demo
  • BLE开发使用说明
  • 701手表2.0.0版本SDK EQ在线调试和离线调试方法 V1.1
  • JL707 手表喇叭输出声音大小评估方法 V1.0
  • JL707 手表音频EQ调试方法 V1.0
  • AC707N 手表通话写卡 软件配置方法
  • 录音功能
  • 701手表2.X.X系列SDK调试EQ配置方法及音频调试技巧V1.1
  • 701手表104版本SDK EQ在线调试和离线调试方法 V1.1
  • mic2dac示例
  • P11 SensorHub相关
  • 手表升级操作文档
  • AC707NGPU
  • DBI模块介绍
  • GPU模块介绍
  • 701N屏幕驱动配置说明
  • 701N_UI编辑工具用户手册
  • 支付宝资料
  • 支付宝硬件接入资料
  • 支付宝乘车码接入资料
  • CAT1 接入文档
  • 701N_WATCH_CAT1开发说明
  • Findmy功能
  • music模式相关
  • 707电池曲线
  • 707N内置FLASH挂载FAT文件系统251112_v1.2
  • AC707N_本地视频播放demo(AVI-MJPEG-PCM)
  • 光波导屏幕调试
  • 耳机研发和生产流程 指南
  • 707-NandFlash 代码和UI资源独立烧录方案
  • 彩屏仓时间同步补丁
  • 彩屏仓抖音点赞移植
  • 707LVGLv8双屏开发
  • 707N蓝牙互传图传demo
  • AVIPCM数据流接入AIVOICE
  • Flash分区操作demo
  • 手表发射问题
  • 701_707 双备份升级DEMO
  • 707_乘车码刷码失败问题_共性

707N UI调试指导

📎 原始文档:https://www.kdocs.cn/l/cpnLqID7s45v 707N UI调试指导

相关资料链接

  1. SDK文档获取 image

卡片页面

  1. 卡片页面

    1. 添加卡片 ui_page_list数组列举了要显示的卡片页面编号的宏,宏的值是ui_tools生成的页面路径crc值,如果修改了ui图片的路径需要在宏定义里重新修改宏。
      如图所示在数组里添加要显示的页面的编号宏即可新增一个卡片。
      image 如不能显示,检查以下函数
      image
    2. 卡片切换效果 目前卡片切换有平移、淡入淡出、翻页的效果,这些都是使用基本的仿射变换实现的2d变换,可以自己再去实现别的效果。
  2. 菜单页面

    1. 添加菜单 ui工程上的图标修改更换
      image 菜单映射表,修改以下接口,可以把菜单图标列表的索引值映射到对应的跳转页面上
const static MENU_MAP menu_map[] = {

    {0,     0,         ID_WINDOW_DIAL                    },
    {1,     1,         ID_WINDOW_PHONE                    },
    {2,     2,         ID_WINDOW_NOTICE                },
    {3,     3,         ID_WINDOW_MUSIC_PLAYER            },
    {4,     4,         ID_WINDOW_ALARM                    },
        ....
}
u32 ui_menu_map_by_sel(u32 sel, u32 menu_type);
2. 菜单效果

菜单页面处理主要在ui_sys_param_api.c文件内,从这里可以看到卡片移动的几个效果以及菜单页面的几个效果,根据这些效果可以进一步跟进到流程处理里
image

  1. 表盘页面
    1. 去掉侧边栏 sdk表盘右滑默认是侧边栏,关掉TCFG_UI_ENABLE_LEFT_MENU宏,去掉侧边栏
  2. 按键事件
    1. 按键使用一套简单驱动进行管理,调用结构比较麻烦,总的来说,从下到上分成以下个层次:按键值判断->按键消抖->按键集合收集->发送按键消息->按键事件处理。分成ad按键和io按键2种,ad按键就是用电阻值判断按键是否按下,io是用ttl电平判断。
    2. 我们要增加按键事件或者参考按键事件所调用的接口,可以看 ui_key_event_deal_app 函数

3D相关特效代码修改参数API

  1. 立方体模型 cube.h(卡片页面)
/*----------------------------------------------------------------------------*/
/**@brief    立方体模型初始化
   @param    width : 立方体每个面的宽度
   @param    heihgt : 立方体每个面的高度
   @param    w_scale : 立方体每个面宽度的缩放系数
   @param    h_scale : 立方体每个面高度的缩放系数
   @param    view_distance : 视距(值越小, 立方体越大)
   @param    win_x : win区域x坐标偏移
   @param    win_y : win区域y坐标偏移
   @param    win_w : win区域宽度
   @param    win_h : win区域高度
   @note
*/
/*----------------------------------------------------------------------------*/
int cube_init(int width, int height, float w_scale, float h_scale, float view_distance, int win_x, int win_y, int win_w, int win_h);
/*----------------------------------------------------------------------------*/
  1. 足球模型football.h(菜单页面)

/*----------------------------------------------------------------------------*/
/**@brief    足球模型初始化
   @param    width : 足球球面宽度
   @param    height : 足球球面高度
   @param    scale : 足球球面缩放
   @param    view_distance : 视距(值越小, 足球越大)
   @param    win_x : win区域x坐标偏移
   @param    win_y : win区域y坐标偏移
   @param    win_w : win区域宽度
   @param    win_h : win区域高度
   @note
*/
/*----------------------------------------------------------------------------*/
int football_init(int width, int height, float scale, float view_distance, int win_x, int win_y, int win_w, int win_h);
/*----------------------------------------------------------------------------*/

UI 操作示例

  1. 概述 该文档描述了一个用于耳机EQ(均衡器)控制的用户界面(UI)操作示例。该示例展示了如何通过触摸事件来切换EQ模式,并根据耳机的连接状态更新UI元素。
  2. 功能描述
  • EQ模式切换:用户可以通过触摸“下一步”和“上一步”按钮来切换EQ模式。
  • 连接状态指示:根据耳机的连接状态,UI会显示不同的图标(连接或断开)。
  • 动态更新:在UI初始化和状态变化时,相关文本和图标会自动更新。
  1. 主要组件

  2. 3.1UI工程模式页面 添加页面并增加相关图片文字控件,命名好控件的名字
    image

  3. 3.2宏定义 定义了一些常量和状态,用于控制UI行为。

#define LOG_TAG_CONST       UI // 关闭当页的log_xx打印
#define CURR_PAGE           PAGE_72//    添加页面
#define NEXT_BUTTON         CS_IMG_EQ_NEXT//    下一步
#define LAST_BUTTON         CS_IMG_EQ_PRE//    上一步
#define SMALLWIN            CS_TEXT_EQ_MODE//    EQ显示文本
  1. UI 事件注册 使用 REGISTER_UI_EVENT_HANDLER 宏注册UI事件处理程序,以便在特定控件上处理状态变化和触摸事件。
//    EQ显示文本
REGISTER_UI_EVENT_HANDLER(SMALLWIN)
    .onchange = my_onchange,    //用于初始化状态和响应绘图事件
    .ontouch = NULL;    
//    下一步
REGISTER_UI_EVENT_HANDLER(NEXT_BUTTON)
    .    onchange = my_onchange,    //用于初始化状态和响应绘图事件
    .ontouch = my_ontouch;    //触摸事件
//    上一步
REGISTER_UI_EVENT_HANDLER(LAST_BUTTON)
    .onchange = my_onchange,    //用于初始化状态和响应绘图事件
    .ontouch = my_ontouch;    //触摸事件

  1. 4.1状态枚举 定义了图标状态的枚举类型,用于表示耳机的连接状态。
typedef enum {
    ICON_STATUS_DISCONNECT = 0,
    ICON_STATUS_CONNECT,
    ICON_STATUS_PRESSING,
} ICON_STATUS;
  1. 事件处理
  2. 5.1触摸事件处理 my_ontouch 函数处理触摸事件,包括按下和抬起事件。根据当前耳机状态,更新图标并切换EQ模式。
static int my_ontouch(void *_ctrl, struct element_touch_event *e)
{
    struct ui_pic *pic = (struct ui_pic *)_ctrl;
    switch (e->event) {
    case ELM_EVENT_TOUCH_DOWN:
        return true;    //    控件接管消息
    case ELM_EVENT_TOUCH_UP:
        //过滤非点击动作
        if(e->move_flag){
            return false;
        }
        //未连接
        if(!getbox()->earphone_state){
            //发送弹窗提示并返回
            ui_pic_show_image(pic, ICON_STATUS_DISCONNECT);
            ui_server_msg_post("BarTop:Type=%4" , 5);
            return false;
        }

        //  触发按钮点击动效
        ui_pic_show_image(pic, ICON_STATUS_PRESSING);
        os_time_dly(10);
        ui_pic_show_image(pic, ICON_STATUS_CONNECT);

        //  响应动作
        struct element *elm = _ctrl;
        switch(elm->id) {
            case NEXT_BUTTON:
                NOW_EQ_MODE = NOW_EQ_MODE>=4?0:NOW_EQ_MODE+1;
                break;
            case LAST_BUTTON:
                NOW_EQ_MODE = NOW_EQ_MODE==0?4:NOW_EQ_MODE-1;
                break;
        }

        g_printf("NOW_EQ_MODE %d", NOW_EQ_MODE);

        //  发送EQ指令
        custom_client_send_eq_mode(NOW_EQ_MODE);

        //  更新EQ文字窗口
        ui_text_show_index_by_id(SMALLWIN, NOW_EQ_MODE);
        break;
    default :
        break;
    }
    return false;
}

  1. 5.2状态更新 EQ_UPDATA 和 BT_UPDATA 函数用于跨线程消息转发方式更新EQ模式和蓝牙连接状态的显示。
static int EQ_UPDATA(const char *type, u32 arg)
{
    //    更新EQ模式
    ui_text_show_index_by_id(SMALLWIN, NOW_EQ_MODE);
}
static int BT_UPDATA(const char *type, u32 arg)
{
    //    更新按钮状态
    ui_text_show_index_by_id(LAST_BUTTON, CONNECT_STATE?ICON_STATUS_CONNECT:ICON_STATUS_DISCONNECT);
    ui_text_show_index_by_id(NEXT_BUTTON, CONNECT_STATE?ICON_STATUS_CONNECT:ICON_STATUS_DISCONNECT);
}
static const struct uimsg_handl ui_msg_handler[] = {
    { "EQ_UPDATA",        EQ_UPDATA     }, 
    { "BT_UPDATA",        BT_UPDATA     },
    { NULL, NULL},      /* 必须以此结尾! */
};

//    当前页面消息回调注册,CURR_PAGE是页面ID  
case ON_CHANGE_INIT:
    ui_register_msg_handler(CURR_PAGE, ui_msg_handler);
  1. 5.3定时器更新 update_timer 函数定期发送更新消息,以确保UI状态的实时性。
static void update_timer(void *p) {
    UI_MSG_POST("EQ_UPDATA");
    UI_MSG_POST("BT_UPDATA");
}
  1. 完整示例代码
/*
 * @Author: lm
 * @Date: 2024-07-20 15:23:11
 * @LastEditors: lm
 * @LastEditTime: 2024-07-20 15:23:11
 * @Description: file content
 * @FilePath: \sdk\apps\watch\ui\lcd\STYLE_SCREECBOX\screenbox_ui_noise.c
 */

#include "app_config.h"
#include "jlui_app/ui_style.h"
#include "jlui/ui.h"
#include "ui/ui_api.h"
#include "app_task.h"
#include "system/timer.h"
#include "device/device.h"
#include "key_event_deal.h"
#include "res/resfile.h"
#include "jlui_app/res_config.h"
#include "jlui_app/ui_resource.h"
#include "system/includes.h"
#include "audio_config.h"
#include "asm/mcpwm.h"
#include "jlui_app/ui_sys_param.h"
#include "jlui_app/watch_syscfg_manage.h"
#include "font/language_list.h"
#include "bt_common.h"
#include "btstack/btstack_task.h"
#include "btstack/avctp_user.h"
#include "custom_cfg.h"
// #include "product_info_api.h"
#include "cat1/cat1_common.h"
#include "screen_trans/smartbox_user_app.h"
#include "events_adapter.h"

#define LOG_TAG_CONST       UI
#define LOG_TAG             "[UI-ACTION]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".ui_eq.data.bss")
#pragma data_seg(".ui_eq.data")
#pragma const_seg(".ui_eq.text.const")
#pragma code_seg(".ui_eq.text")
#endif

#define STYLE_NAME  JL

#if 1
typedef enum {
    ICON_STATUS_DISCONNECT = 0,
    ICON_STATUS_CONNECT,
    ICON_STATUS_PRESSING,
} ICON_STATUS;

#define     CURR_PAGE           PAGE_72
#define     NEXT_BUTTON         CS_IMG_EQ_NEXT
#define     LAST_BUTTON         CS_IMG_EQ_PRE
#define     SMALLWIN            CS_TEXT_EQ_MODE
#define     CONNECT_STATE       (getbox()->earphone_state)
#define     NOW_EQ_MODE         (getbox()->eq_mode)
#define     RLOAD   0

static int my_ontouch(void *_ctrl, struct element_touch_event *e)
{
    struct ui_pic *pic = (struct ui_pic *)_ctrl;
    switch (e->event) {
    case ELM_EVENT_TOUCH_DOWN:
        return true;
    case ELM_EVENT_TOUCH_UP:
        if(e->move_flag){
            return false;
        }

        if(!getbox()->earphone_state){
            ui_pic_show_image(pic, ICON_STATUS_DISCONNECT);
            ui_server_msg_post("BarTop:Type=%4" , 5);
            return false;
        }

        //  按钮动效
        ui_pic_show_image(pic, ICON_STATUS_PRESSING);
        os_time_dly(10);
        ui_pic_show_image(pic, ICON_STATUS_CONNECT);

        struct element *elm = _ctrl;
        switch(elm->id) {
            case NEXT_BUTTON:
                NOW_EQ_MODE = NOW_EQ_MODE>=4?0:NOW_EQ_MODE+1;
                break;
            case LAST_BUTTON:
                NOW_EQ_MODE = NOW_EQ_MODE==0?4:NOW_EQ_MODE-1;
                break;
        }

        g_printf("NOW_EQ_MODE %d", NOW_EQ_MODE);

        //  发送EQ指令。。
        custom_client_send_eq_mode(NOW_EQ_MODE);

        //  更新文字窗口
        ui_text_show_index_by_id(SMALLWIN, NOW_EQ_MODE);

        break;
    default :
        break;
    }
    return false;
}

static int EQ_UPDATA(const char *type, u32 arg)
{
    ui_text_show_index_by_id(SMALLWIN, NOW_EQ_MODE);
}
static int BT_UPDATA(const char *type, u32 arg)
{
    ui_text_show_index_by_id(LAST_BUTTON, CONNECT_STATE?ICON_STATUS_CONNECT:ICON_STATUS_DISCONNECT);
    ui_text_show_index_by_id(NEXT_BUTTON, CONNECT_STATE?ICON_STATUS_CONNECT:ICON_STATUS_DISCONNECT);
}
static const struct uimsg_handl ui_msg_handler[] = {
    { "EQ_UPDATA",        EQ_UPDATA     }, 
    { "BT_UPDATA",        BT_UPDATA     },
    { NULL, NULL},      /* 必须以此结尾! */
};

static void update_timer(void *p){
    UI_MSG_POST("EQ_UPDATA");
    UI_MSG_POST("BT_UPDATA");
}

static int my_onchange(void *_ctrl, enum element_change_event event, void *arg)
{
    struct element *elm = (struct element *)_ctrl;
    struct ui_text *text = elm;
    struct ui_pic *pic = elm;
    struct draw_context *dc = (struct draw_context *)arg;
    static int id = 0;
    switch (event) {
        case ON_CHANGE_INIT:
            ui_register_msg_handler(CURR_PAGE, ui_msg_handler);
            //  各个控件初始化
            switch(elm->id) {
                case SMALLWIN:  
                    ui_text_set_index(text, NOW_EQ_MODE);
                    break;
                case NEXT_BUTTON:  
                    ui_pic_set_image_index(pic, (CONNECT_STATE==1)?ICON_STATUS_CONNECT:ICON_STATUS_DISCONNECT);
                    break;
                case LAST_BUTTON:
                    ui_pic_set_image_index(pic, (CONNECT_STATE==1)?ICON_STATUS_CONNECT:ICON_STATUS_DISCONNECT);
                    break;
            }
            if(!id) id = sys_timer_add(NULL, update_timer, 500);
            break;
        case ON_CHANGE_RELEASE:
            if(id){
                sys_timer_del(id);
                id = 0;
            }
            break;
    }
    return false;
}

REGISTER_UI_EVENT_HANDLER(SMALLWIN)
    .onchange = my_onchange,
   .onkey = NULL,
   .ontouch = NULL,
};

REGISTER_UI_EVENT_HANDLER(NEXT_BUTTON)
    .onchange = my_onchange,
   .onkey = NULL,
   .ontouch = my_ontouch,
};

REGISTER_UI_EVENT_HANDLER(LAST_BUTTON)
    .onchange = my_onchange,
   .onkey = NULL,
   .ontouch = my_ontouch,
};

#else
void noise_ctrl_anc_off( u8 anc_mode)
{

}

#endif
  1. 结论 该UI操作示例展示了如何通过触摸事件实现耳机EQ模式的切换,并根据耳机的连接状态动态更新UI元素。通过合理的事件处理和状态管理,用户可以获得流畅的操作体验。

简单表盘进入缩放动效示例

在static int WATCH_onchange(void *ctr, enum element_change_event e, void *arg)添加以下函数,在第一次进入页面时动画与ID绑定,并触发动画效果

    case ON_CHANGE_FIRST_SHOW:
        //    卡片过渡时返回
        if(ui_card_get_status()) break;
        //    获取表盘页面ID
        struct element * curr_elm = ui_core_get_element_by_id(DIAL_PAGE_0);
        r_printf("%s %d %d %d ", __func__, __LINE__, curr_elm->css.left, ui_card_get_status());
        //    缩放初始与结束值,归一化256
        int start_pos  = 512;
        int end_pos =  256;
        //    创建动画句柄
        ui_anim_t a={0};
        ui_anim_init(&a);
        //    绑定ID与动画
        ui_anim_set_var(&a, elm->parent->id);
        //    选择贝塞曲线
        ui_anim_set_path_cb(&a, ui_anim_path_ease_out);
        //    动作回调
        ui_anim_set_exec_cb(&a, watch_enter_anim_cb2);
        //    设置动画起始结束值
        ui_anim_set_values(&a, start_pos, end_pos);
        //    整个动画的持续时间
        ui_anim_set_time(&a, 80);
        //    启动动画
        ui_anim_start(&a);
        break;

并在动画回调中处理更改控件的动作

static void watch_enter_anim_cb2(int var, int v)
{
    //    ID获取ELM
    struct element *elm = ui_core_get_element_by_id(var);
    if (!elm) {
        return;
    }
    //    设置控件运动属性
    if(v == 256){
        ui_core_set_element_ratio_en(elm, 0);
    } else {
        ui_core_set_element_ratio(elm, (float)v/256.0, (float)v/256.0, 1);
    }
    //    绘制
    ui_core_redraw(elm);
}