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_乘车码刷码失败问题_共性

UI入门简单实列

📎 原始文档:https://www.kdocs.cn/l/clG1N5VuQ58s UI入门简单实列
示例将展现的内容包括:列表的创建与使用、多张图片切换显示、文字控件strpic和text格式的显示和使用、数字控件string格式和numb格式的使用、不同方式的页面切换和数据源的使用。

//页面id管理
#define     USR_TE_GRID_PAGE            PAGE_39         //测试列表页面
#define     USR_TE_PIC_PAGE             PAGE_40         //测试图片页面
#define     USR_TE_TEXT_PAGE            PAGE_41         //测试文本页面
#define     USR_TE_NUMB_PAGE            PAGE_42         //测试数字页面

//垂直列表选中的布局id
#define     USR_TE_SWITCH_PIC            TE_SWITCH_PIC_LAYOUT
#define     USR_TE_SWITCH_TEXT           TE_SWITCH_TEXT_LAYOUT
#define     USR_TE_SWITCH_NUMB           TE_SWITCH_NUMB_LAYOUT

//控件id管理
#define     USR_TE_VERTLIST             TE_VERTLIST     //垂直列表id
#define     USR_TE_PIC                  TE_PIC          //图片控件id
#define     USR_TE_TEXT_NAME            TE_TEXT_NAME    //文本控件蓝牙名id
#define     USR_TE_TEXT_ADDR            TE_TEXT_ADDR    //文本控件蓝牙地址id
#define     USR_TE_TEXT_VER             TE_TEXT_VER     //文本控件版本号id
#define     USR_TE_NUMB_NUM             TE_NUMB_NUM     //数字控件TYPE_NUM格式  
#define     USR_TE_NUMB_STR             TE_NUMB_STR     //数字控件TYPE_STRING格式
1.新建列表控件

首先每新建一个页面后需要添加图层和布局(带背景颜色),因为所有控件都需要在布局中使用。列表控件有垂直列表和水平列表,列表是带有滑动效果的,所以不需要编写滑动逻辑。但客户软件可以配置滑动方向。添加列表后如下图一样右键添加行、设置行高和间隔即可。设置好列表格式后会得到与添加行对应数量布局,只需要像下图一样添加想要显示的内容即可。下面通过添加strpic格式的文字控件作为示例,实现点击不同的项会进入不同界面的功能
imageimage

typedef struct usr_menu_callback {
    int sel_id;
    int (*exit_check)();
    int window;
    int (*enter_check)(int window);
} USR_MENU_CB;

const static USR_MENU_CB usr_menu_cb[] = {
  
    //{被选中的id,  退出检查, ,进入的页面id, ,进入检查},
    {USR_TE_SWITCH_PIC, NULL, USR_TE_PIC_PAGE, NULL}, 
    {USR_TE_SWITCH_TEXT, NULL, USR_TE_TEXT_PAGE, NULL}, 
    {USR_TE_SWITCH_NUMB, NULL, USR_TE_NUMB_PAGE, NULL},
};

//此处初始化的时候只需要限制一下滑动的方向
static int usr_test_grid_onchane(void *ctr, enum element_change_event e, void *arg)
{
    struct ui_grid *grid = (struct ui_grid *)ctr;
    switch (e) {
    case ON_CHANGE_INIT:
        ui_grid_set_slide_direction(grid, SCROLL_DIRECTION_UD);
        break;
    case ON_CHANGE_RELEASE:
        break;
    case ON_CHANGE_FIRST_SHOW:
        break;
    default:
        return false;
    }
    return false;
}


//选择处理
static int usr_menu_in_sel(struct ui_grid *grid)
{
    u32 sel_item = ui_grid_cur_item(grid);

    if (sel_item >= grid->avail_item_num) {
        return false;
    }
    int id = grid->item[sel_item].elm.id;

    for (int i = 0; i < (sizeof(usr_menu_cb) / sizeof(usr_menu_cb[0])); i++) {
        if (usr_menu_cb[i].sel_id == id) {
            printf("menu layout id = %x \n", id);
            if (usr_menu_cb[i].window) {
                if (usr_menu_cb[i].enter_check && (!usr_menu_cb[i].enter_check(usr_menu_cb[i].window))) {
                    return false;
                }
                UI_HIDE_CURR_WINDOW();
                UI_SHOW_WINDOW(usr_menu_cb[i].window);
            }
            return true;
            break;
        }
    }
    return false;
}

//列表控件滑动功能底层以及做好,所以只需要做点击选择切页面功能
static int usr_test_grid_ontouch(void *ctr, struct element_touch_event *e)
{
    struct ui_grid *grid = (struct ui_grid *)ctr;
    int sel_item;
    static u8 move_flag = 0;
    switch (e->event) {
    case ELM_EVENT_TOUCH_R_MOVE:
        break;
    case ELM_EVENT_TOUCH_L_MOVE:
        break;
    case ELM_EVENT_TOUCH_MOVE:
        move_flag = 1;
        return false;//不接管消息
        break;
    case ELM_EVENT_TOUCH_DOWN:
        move_flag = 0;
        return false;//不接管消息
        break;
    case ELM_EVENT_TOUCH_UP:
        if (move_flag) {
            move_flag = 0;
            return false;//不接管消息
        }
        return usr_menu_in_sel(grid);
        break;
    default:
        return false;
        break;
    }
    return true;//接管消息
}

//通过这种方式注册布局或者控件,实现软件控制UI各种动作
REGISTER_UI_EVENT_HANDLER(USR_TE_VERTLIST)
.onchange = usr_test_grid_onchane,
 .onkey = NULL,
  .ontouch = usr_test_grid_ontouch,
};
2.新建图片控件

同样往新建的页面中添加好图层和布局(需要填充背景颜色),然后在需要的位置添加上图片控件,本示例将通过图片列表的方式添加多张图片,然后通过定时器不断的刷新切换不同的图片。
image

#define MAX_PIC_NUMBS           7

static void usr_pic_reflash(void)
{
    static u8 CurrPicIndex = 0;
    if(++CurrPicIndex >= MAX_PIC_NUMBS){
        CurrPicIndex = 0;
    }
    ui_pic_show_image_by_id(USR_TE_PIC ,CurrPicIndex);
} 

static int usr_test_pic_onchange(void *ctr, enum element_change_event e, void *arg)
{
    struct ui_pic *pic = (struct ui_pic *)ctr;
    static u16 pic_timer_id = 0;
    switch (e) {
    case ON_CHANGE_INIT:
        if(!pic_timer_id){
            pic_timer_id = sys_timer_add(NULL , usr_pic_reflash , 1000);
        }
        //默认进入显示第几张图片
        ui_pic_set_image_index(pic ,2);
        break;
    case ON_CHANGE_FIRST_SHOW:
    
        break;
    case ON_CHANGE_RELEASE:
        if(pic_timer_id){
            sys_timer_del(pic_timer_id);
            pic_timer_id = 0;
        }
        break;
    default:
        return false;
    }
    return false;
}


REGISTER_UI_EVENT_HANDLER(USR_TE_PIC)
.onchange = usr_test_pic_onchange,
 .onkey = NULL,
  .ontouch = NULL,
};

static int usr_change_page_ontouch(void *ctr, struct element_touch_event *e)
{
    struct window *window = (struct window *)ctr;
    printf("%s:e->event=%d" , __func__ , e->event);
    switch (e->event) {
    case ELM_EVENT_TOUCH_R_MOVE:
        ui_send_event(KEY_CHANGE_PAGE , USR_TE_GRID_PAGE|BIT(31));
        return false;
    case ELM_EVENT_TOUCH_L_MOVE:
        ui_send_event(KEY_CHANGE_PAGE , USR_TE_GRID_PAGE|BIT(31));
        return false;
    default:
        break;
    }
    return false;
}

REGISTER_UI_EVENT_HANDLER(USR_TE_PIC_PAGE)
.onchange = NULL,
 .onkey = NULL,
  .ontouch = usr_change_page_ontouch,
};
3.新建文本控件

文本控件格式分为ascii、strpic、text三种格式,strpic格式使用的是多国语言表中设置好的文本,一般会使用在菜单、标题等固定显示的页面;text格式是使用字库进行显示,一般使用在消息通知、歌词显示等不固定内容显示。同样往新建的页面中添加好图层和布局(需要填充背景颜色),然后添加对应的文字控件。本示例将使用三个text格式的文本控件,通过数据源作为区分,分别显示蓝牙名、mac地址和版本号内容。
image

//text 格式显示
extern const u8 *bt_get_mac_addr();
extern const char *bt_get_local_name();
static u8 VStr[]="v1.0.0";

static int usr_test_text_onchange(void *ctr, enum element_change_event e, void *arg)
{
    struct ui_text *text = (struct ui_text *)ctr;
    u8 * buf;
    u8 * addr_buf = NULL ;
    u8 mac_addr[6] = {0};
    switch (e) {
    case ON_CHANGE_INIT:
        if (!strcmp(text->source, "name")) {
            buf = bt_get_local_name();
            ui_text_set_text_attrs(text , buf , strlen(buf) , FONT_ENCODE_UTF8 , FONT_ENDIAN_SMALL , FONT_DEFAULT);
        }
        else if (!strcmp(text->source, "addr")){
            //log_info("set bt addr");
            memcpy(mac_addr, bt_get_mac_addr(), 6);
            put_buf(mac_addr ,6);
            addr_buf = malloc (20);
            if(addr_buf == NULL){
                ASSERT(0, "addr_buf malloc fail");
            }
            for(u8 i = 0 ; i < 6 ; i++){
                if(i == 0 ){
                    sprintf(addr_buf , "%X%c",mac_addr[i],':');
                }
                else if (i < 5){
                    sprintf(addr_buf , "%s%X%c",addr_buf ,mac_addr[i] ,':');
                }
                else{
                    sprintf(addr_buf , "%s%X",addr_buf ,mac_addr[i]);
                }
            } 
            ui_text_set_text_attrs(text , addr_buf , strlen(addr_buf) , FONT_ENCODE_UTF8 , FONT_ENDIAN_SMALL , FONT_DEFAULT);
        }
        else if (!strcmp(text->source, "ver")){
            ui_text_set_text_attrs(text , VStr , strlen(VStr) , FONT_ENCODE_UTF8 , FONT_ENDIAN_SMALL , FONT_DEFAULT);
        }
        break;
    case ON_CHANGE_RELEASE:
        if(addr_buf){
            free(addr_buf);
            addr_buf = NULL;
        }
        break;
    }
    return false;
}


REGISTER_UI_EVENT_HANDLER(USR_TE_TEXT_NAME)
.onchange = usr_test_text_onchange,
 .onkey = NULL,
  .ontouch = NULL,
};

REGISTER_UI_EVENT_HANDLER(USR_TE_TEXT_ADDR)
.onchange = usr_test_text_onchange,
 .onkey = NULL,
  .ontouch = NULL,
};

REGISTER_UI_EVENT_HANDLER(USR_TE_TEXT_VER)
.onchange = usr_test_text_onchange,
 .onkey = NULL,
  .ontouch = NULL,
};

static int usr_change_page_ontouch(void *ctr, struct element_touch_event *e)
{
    struct window *window = (struct window *)ctr;
    printf("%s:e->event=%d" , __func__ , e->event);
    switch (e->event) {
    case ELM_EVENT_TOUCH_R_MOVE:
        UI_HIDE_CURR_WINDOW();
        UI_SHOW_WINDOW(-1);
        return false;
    case ELM_EVENT_TOUCH_L_MOVE:
        UI_HIDE_CURR_WINDOW();
        UI_SHOW_WINDOW(-1);
        return false;
    default:
        break;
    }
    return false;
}

REGISTER_UI_EVENT_HANDLER(USR_TE_TEXT_PAGE)
.onchange = NULL,
 .onkey = NULL,
  .ontouch = usr_change_page_ontouch,
};
4.新建数字控件

数字控件有TYPE_STRING和TYPE_NUM两种方式进行显示,两者区别在于TYPE_NUM格式最多只能显示xx/xx这样格式长度的内容,对于xx/xx/xx...这种多位数字格式的内容无法显示,这时候就可以TYPE_STRING进行显示。 同样往新建的页面中添加好图层和布局(需要填充背景颜色),然后添加对应的数字控件。本示例将使用两个数字控件,通过获取RTC的时间,然后使用TYPE_STRING和TYPE_NUM两种方式显示不同长度内容信息。同样使用数据源的格式区分同一个页面中两个数字控件
image

static u8 stopwatch_num_buf[10] = {0};

static void get_sys_time(struct sys_time *time)
{
    void *fd = dev_open("rtc", NULL);
    if (!fd) {
        memset(time, 0, sizeof(*time));
        return;
    }
    dev_ioctl(fd, IOCTL_GET_SYS_TIME, (u32)time);
    /* printf("get_sys_time : %d-%d-%d,%d:%d:%d\n", time->year, time->month, time->day, time->hour, time->min, time->sec); */
    dev_close(fd);
}

void usr_string_reflash(void)
{
    struct sys_time time;
    struct unumber str_unumb;
    struct unumber num_unumb;
    get_sys_time(&time);
    sprintf(stopwatch_num_buf, "%2d%c%2d%c%2d", time.hour, ':', time.min, '.', time.sec);
    str_unumb.type = TYPE_STRING;
    str_unumb.num_str = &stopwatch_num_buf;
    num_unumb.type = TYPE_NUM;
    num_unumb.numbs = 2;
    num_unumb.number[0] = time.min;
    num_unumb.number[1] = time.sec;
    ui_number_update_by_id(USR_TE_NUMB_STR, &str_unumb);
    ui_number_update_by_id(USR_TE_NUMB_NUM, &num_unumb);
}
static int usr_test_num_onchange(void *ctrl, enum element_change_event e, void *arge)
{
    struct ui_number *num = (struct ui_number *) ctrl;
    static u16 numb_timer_id = 0;
    struct unumber unumb;
    struct sys_time time;
    switch (e) {
    case ON_CHANGE_INIT:
        if (!strcmp(num->source, "string")) {
            get_sys_time(&time);
            sprintf(stopwatch_num_buf, "%2d%c%2d%c%2d", time.hour, ':', time.min, '.', time.sec);
            unumb.type = TYPE_STRING;
            unumb.num_str = &stopwatch_num_buf;
            ui_number_update(num, &unumb);
        }
        else if (!strcmp(num->source, "munb")) {
            get_sys_time(&time);
            unumb.type = TYPE_NUM;
            unumb.numbs = 2;
            unumb.number[0] = time.min;
            unumb.number[1] = time.sec;
            ui_number_update(num, &unumb);
        }

        if (!numb_timer_id) {
            numb_timer_id = sys_timer_add(NULL, usr_string_reflash, 500);
        }
        break;
    case ON_CHANGE_RELEASE:
        if(numb_timer_id){
            sys_timer_del(numb_timer_id);
            numb_timer_id = 0;
        }
        break;
    default:
        break;
    }
    return false;
}

REGISTER_UI_EVENT_HANDLER(USR_TE_NUMB_NUM)
.onchange = usr_test_num_onchange,
 .onkey = NULL,
  .ontouch = NULL,
};

REGISTER_UI_EVENT_HANDLER(USR_TE_NUMB_STR)
.onchange = usr_test_num_onchange,
 .onkey = NULL,
  .ontouch = NULL,
};

static int usr_change_page_ontouch(void *ctr, struct element_touch_event *e)
{
    struct window *window = (struct window *)ctr;
    printf("%s:e->event=%d" , __func__ , e->event);
    switch (e->event) {
    case ELM_EVENT_TOUCH_R_MOVE:
        ui_send_event(KEY_CHANGE_PAGE, 1);
        return false;
    case ELM_EVENT_TOUCH_L_MOVE:
        ui_send_event(KEY_CHANGE_PAGE, 1);
        return false;
    default:
        break;
    }
    return false;
}

REGISTER_UI_EVENT_HANDLER(USR_TE_NUMB_PAGE)
.onchange = NULL,
 .onkey = NULL,
  .ontouch = usr_change_page_ontouch,
};