- [BR28 lua_ui开发](#br28-lua_ui开发) - [1. ui控件增加lua属性](#1-ui控件增加lua属性) - [1.1. ui工具中增加luascript属性(以layout为例)](#11-ui工具中增加luascript属性以layout为例) - [1.1.1. 控件模板添加luascript属性](#111-控件模板添加luascript属性) - [1.1.2. 升级ui工程源文件](#112-升级ui工程源文件) - [1.2. BR28 SDK的对应控件添加lua属性(以layout为例)](#12-br28-sdk的对应控件添加lua属性以layout为例) - [1.2.1. lua属性结构定义](#121-lua属性结构定义) - [1.2.2. layout结构添加lua属性](#122-layout结构添加lua属性) - [1.2.2.1. 在控件初始化函数添加 lua onload 代码的调用](#1221-在控件初始化函数添加-lua-onload-代码的调用) - [1.2.2.2. 在控件 ontouch 事件回调函数添加 touch 事件的响应代码执行](#1222-在控件-ontouch-事件回调函数添加-touch-事件的响应代码执行) - [2. 使用lua脚本开发APP](#2-使用lua脚本开发app) - [2.1. lua数据类型](#21-lua数据类型) - [2.2. 常用的lua语法](#22-常用的lua语法) - [2.3. br28 lua库](#23-br28-lua库) - [3. 扩展lua库](#3-扩展lua库) - [3.1 SDK添加lua扩展接口和库代码](#31-sdk添加lua扩展接口和库代码) - [3.1.1 常用的lua CAPI](#311-常用的lua-capi) - [3.1.2 br28 SDK用C语言添加一个lua库](#312-br28-sdk用c语言添加一个lua库) - [3.1.3 br28 lua库结构](#313-br28-lua库结构) - [3.1.4 br28 gui库结构](#314-br28-gui库结构) - [3.2 模拟器添加lua扩展模拟接口](#32-模拟器添加lua扩展模拟接口) - [4. 使用lua模拟UI效果](#4-使用lua模拟ui效果) - [4.1 创建button控件](#41-创建button控件) - [4.2 编辑lua代码](#42-编辑lua代码) - [4.3 启动模拟器](#43-启动模拟器) - [4.4 小机运行验证](#44-小机运行验证) - [5 现有的lua接口](#5-现有的lua接口) - [5.1 GUI 库](#51-gui-库) - [5.1.1 函数接口介绍模板](#511-函数接口介绍模板) - [5.1.1 获取控件对象](#511-获取控件对象) - [5.1.2 页面切换](#512-页面切换) - [5.1.3 返回上一页](#513-返回上一页) - [5.1.4 检查上一层页面](#514-检查上一层页面) # BR28 lua_ui开发 ## 1. ui控件增加lua属性     br28 SDK的UI控件可添加使用脚本语言lua开发的方法,控件中添加lua属性后即可通过ui工具作为IDE进行lua脚本开发,实现在windows系统中开发br28项目APP的目的。
    注意:ui工具和SDK对应的控件属性要一致,如果SDK中对控件添加lua脚本调用,UI工具中未添加lua脚本属性,或者反之。则执行时可能出现不可预测的后果。 ## 1.1. ui工具中增加luascript属性(以layout为例) 如果要在已有工程中添加lua属性,则需按照下面方法: 1. 在控件模板中添加luascript属性描述; 2. 使用源文件升级工具将已有的工程源文件进行升级; 3. 重启ui编辑工具进行lua编程开发。 ### 1.1.1. 控件模板添加luascript属性 UI工程目录下有控件模板文件control.json,路径为: > 基本控件: > > UI工程/UITools/control/control.json > > 自定义控件: > > UI工程/UITools/control/ex/xxx.json 使用文本编辑工具打开json文件,找到layout控件定义部分,在**action属性后面**添加luascript属性描述。内容如下: ```json { "-name": "luascript", "-type": "luascript", "caption": "Lua脚本", "luascript": [{ "event": "ONLOAD", "type": 0, "code": "" },{ "event": "UNLOAD", "type": 1, "code": "" },{ "event": "TOUCH_DOWN", "type": 2, "code": "" },{ "event": "TOUCH_MOVE", "type": 3, "code": "" },{ "event": "TOUCH_R_MOVE", "type": 4, "code": "" },{ "event": "TOUCH_L_MOVE", "type": 5, "code": "" },{ "event": "TOUCH_D_MOVE", "type": 6, "code": "" },{ "event": "TOUCH_U_MOVE", "type": 7, "code": "" },{ "event": "TOUCH_HOLD", "type": 8, "code": "" },{ "event": "TOUCH_UP", "type": 9, "code": "" }] } ``` ### 1.1.2. 升级ui工程源文件 在“UI工程”目录的路径下找到升级工具文件: > UI工程/UITools/UI工程源文件升级工具.exe 双击运行该程序得如下界面:
根据图中序号进行操作: 1. 选择控件模板文件; > 这里选择刚刚修改的“UI工程/UITools/control/control.json”文件 2. 选择待升级的ui工程源文件; > br28的UI工程“模式界面”源文件为:“UI工程\ui_240x240_watch\模式界面\project\BT_Watch.json” 3. 选择升级后输出的文件路径及名称; > 一般将待转换的源文件备份后直接使用源文件命名,升级的源文件使用备份文件。升级完成后即可直接使用升级后的文件。 4. 点击转换升级,等待进度条完成。 > 等待“转换进度”的进度条完成即可。注意br23工程文件升级br28的话,需将“ImageType”选项选中。 至此完成对UI工程源文件的升级,根据模板,升级工具会自动将UI工程源文件中对应控件添加lua属性。此时打开“UI绘图工具”属性栏部分会增加“lua脚本”按钮,点击即弹出lua脚本编辑窗口,UI工具中lua属性添加完成。
## 1.2. BR28 SDK的对应控件添加lua属性(以layout为例) ### 1.2.1. lua属性结构定义 在BR28 SDK的UI库的头文件“contol.h”中定义lua结构为: ```c // lua事件类型 enum luascript_event_type { LUA_EVENT_ONLOAD = 0, LUA_EVENT_UNLOAD, LUA_EVENT_TOUCH_DOWN, LUA_EVENT_TOUCH_MOVE, LUA_EVENT_TOUCH_R_MOVE, LUA_EVENT_TOUCH_L_MOVE, LUA_EVENT_TOUCH_D_MOVE, LUA_EVENT_TOUCH_U_MOVE, LUA_EVENT_TOUCH_HOLD, LUA_EVENT_TOUCH_UP, }; // lua属性结构 struct luascript_code { u16 type; u16 argc; char argv[0]; }; // ui资源结构 struct element_luascript { u16 num; u16 nop; //FFFF struct luascript_code code[0]; }; struct element_luascript_t { u16 num; u16 nop; //FFFF struct luascript_code *code[10]; }; ``` 其中,**枚举变量“luascript_event_type”定义的lua事件类型与上述控件模板中添加的“luascript属性”对应**,枚举值为luasctipt属性的“type”属性。 ### 1.2.2. layout结构添加lua属性 在layout控件的结构体内添加lua属性,注意与UI工具中添加的顺序一致。结构体代码为: ```c struct layout_info { struct ui_ctrl_info_head head; struct element_event_action *action; // lua属性 struct element_luascript_t *lua; union ui_control_info *ctrl; }; ``` > 注意:action 结构为UI工具中“事件属性”对应的属性,我们在UI工具中控件的 lua 属性添加到事件之后,因此这里的结构要将 lua 结构添加到 action 之后。 在 layout.h 头文件中的 layout 结构添加 lua 属性指针,代码为: ```c struct layout { struct element elm; //must be first u8 hide: 1; u8 inited: 1; u8 release: 6; // u8 css_num:5; // u32 css[2]; u8 page; struct element_luascript_t *lua; struct layout *layout; const struct layout_info *info; const struct element_event_handler *handler; }; ``` 在 layout.c 中添加对 lua 代码的获取与调用: #### 1.2.2.1. 在控件初始化函数添加 lua onload 代码的调用     onload 代码我们放在控件初始化时,即 change 事件的 ON_CHANGE_INIT 中调用,那么我们需要在控件新创建时记录下相关的lua信息,然后再到对于事件中添加 lua 代码读取和执行的内容。 1. 找到控件“初始化”或“创建新控件”函数,layout控件的初始化函数为 ```c int layout_init(struct layout *layout, struct layout_info *__info, struct element *parent, bool init); ``` 2. 记录 lua 相关信息 ```c struct layout_info *info = (struct layout_info *)ui_core_load_widget_info(__info, -1); layout->info = __info; /* 记录控件所在页面和lua代码信息 */ layout->page = info->head.page; layout->lua = info->lua; ``` 3. 在控件 onchange 回调中添加 lua onload 和 unload 代码获取和执行 ```c static int layout_onchange(void *_layout, enum element_change_event event, void *arg) { struct layout *layout = (struct layout *)_layout; int lua_running = 0; /* lua代码执行标志 */ struct luascript_code *lua_code = NULL; /* lua 代码结构 */ struct element_luascript_t *elm_lua = NULL; /* 控件中 lua 代码属性 */ if (layout->release) { if (event == ON_CHANGE_RELEASE_PROBE) { ui_core_release_child_probe(&layout->elm); return false; } if (event == ON_CHANGE_RELEASE) { if (ENABLE_LUA_VIRTUAL_MACHINE) { /* 在 ON_CHANGE_ERELEASE 事件中执行lua unload代码 */ elm_lua = (struct element_luascript_t *)ui_core_load_lua(layout->page, layout->lua); /* 从UI资源中读取lua源码 */ if (luascript_code_find(elm_lua, LUA_EVENT_UNLOAD, &lua_code)) { /* 搜索unload代码并执行 */ lua_running = run_lua_string(lua_code->argc, &lua_code->argv); } ui_core_free_lua(elm_lua); /* 释放lua源码占用的资源 */ } if (layout->handler && layout->handler->onchange) { layout->handler->onchange(layout, event, arg); } ui_core_remove_element(&layout->elm); ui_core_free(layout); return true; } } if (!layout->inited) { return false; } if (ENABLE_LUA_VIRTUAL_MACHINE) { if (event == ON_CHANGE_INIT || event == ON_CHANGE_UPDATE_ITEM) { /* 在 ON_CHANGE_INIT 事件中执行onload代码 */ elm_lua = (struct element_luascript_t *)ui_core_load_lua(layout->page, layout->lua); if (luascript_code_find(elm_lua, LUA_EVENT_ONLOAD, &lua_code)) { lua_running = run_lua_string(lua_code->argc, &lua_code->argv); } ui_core_free_lua(elm_lua); } /* 默认不 return */ if (lua_running) { return true; } } if (layout->handler && layout->handler->onchange) { if (layout->handler->onchange(layout, event, arg)) { return true; } } switch (event) { case ON_CHANGE_HIGHLIGHT: layout_highlight(layout, (int)arg); break; case ON_CHANGE_SHOW_POST: custom_draw_callback(layout, arg); // 先预留,后续自定义绘图可能要在这里实现 break; default: break; } return true; } ``` 4. 需注意的几个函数接口含义 ```c // 加载lua代码 // 该函数会在指定的UI页资源中加载lua代码并自动申请控件存储,将内存指针返回 elm_lua = (struct element_luascript_t *)br28_load_lua(info->head.page, info->lua); ``` ```c // 搜索lua代码块 // 该函数会在 elm_lua 指针的内存中搜索指定事件“LUA_EVENT_ONLOAD” 的代码,并将其指针赋值给 lua_code,如果成功找到则返回true,否则返回false luascript_code_find(elm_lua, LUA_EVENT_ONLOAD, &lua_code) ``` ```c // 执行lua代码,其中参数argc为源码字符串长度,参数argv为源码字符串指针 lua_running = run_lua_string(lua_code->argc, &lua_code->argv); ``` ```c // 释放elm_lua内存 ui_core_free_lua(elm_lua); ``` #### 1.2.2.2. 在控件 ontouch 事件回调函数添加 touch 事件的响应代码执行 ontouch事件处理函数如下,根据br28 ui资源的存放机制,在调用该代码之前需要主动加载lua代码,而后再执行。 ```c static int layout_ontouch(void *_layout, struct element_touch_event *e) { struct layout *layout = (struct layout *)_layout; int lua_code = 0; struct element_luascript_t *elm_lua = NULL; if (!layout->inited) { return false; } if (ENABLE_LUA_VIRTUAL_MACHINE) { // 加载 lua 源码资源 elm_lua = (struct element_luascript_t *)ui_core_load_lua(layout->page, layout->lua); // 执行 touch 对于事件源码,该函数定义在 control.h 中 lua_code = lua_touch_event_run(elm_lua, e); ui_core_free_lua(elm_lua); if (lua_code) { return true; } } if (layout->handler && layout->handler->ontouch) { if (layout->handler->ontouch(layout, e)) { return true; } } return false; } ``` 注意:由于lua回调可能会调用自身资源,因此在执行onload部分代码时,应当先让控件初始化完成再执行onload代码。同样在控件使用release释放自身资源之前执行lua unload部分代码 ## 2. 使用lua脚本开发APP     通过章节一已经完成在ui源文件和SDK中添加lua脚本属性,接下来使用新版UI工具运用lua脚本开发APP,同时例用lua模拟器在windows系统下完成预调试。在模拟器运行无误后再将编译的UI资源文件下载到项目的flash中,在小机中完成最终测试。 ### 2.1. lua数据类型     lua 是一种无类型的解释语言,其变量无需像C语言一样声明变量类型,在变量初始化时解释器会自动确定该变量的类型。 |编号|数据类型|描述| |:-----:|:-----:|:-----| |1|nil|用于区分值与某些数据或没有(nil)数据| |2|boolean|包括 true 和 false 作为值,通常用于条件检查| |3|number|表示实数(双精度浮点)数字| |4|string|表示字符数组| |5|function|表示用C或者lua编写的方法(函数)| |6|userdata|表示任意C语言数据| |7|thread|表示独立的执行线程,它用于实现协同程序| |8|table|表示普通数组,符号表,集合,记录,图形,树等,并实现关联数组。它可以保存任何值(除了nil)| > 注意: > > table (table)是 lua 中一种功能强大的数据结构,可以用它创建不同的数据类型,如:数组、字典等 > * Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。 > * Lua table 是不固定大小的,你可以根据自己需要进行扩容。 > * Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用"format"来索引table string。 > > ```lua > -- 简单的 table > mytable = {} > print("mytable 的类型是 ",type(mytable)) > > mytable[1]= "Lua" > mytable["wow"] = "修改前" > print("mytable 索引为 1 的元素是 ", mytable[1]) > print("mytable 索引为 wow 的元素是 ", mytable["wow"]) > > -- alternatetable和mytable的是指同一个 tabl > alternatetable = mytable > > print("alternatetable 索引为 1 的元素是 ", alternatetable[1]) > print("mytable 索引为 wow 的元素是 ", alternatetable["wow"]) > alternatetable["wow"] = "修改后" > > print("mytable 索引为 wow 的元素是 ", mytable["wow"]) > > -- 释放变量 > alternatetable = nil > print("alternatetable 是 ", alternatetable) > > -- mytable 仍然可以访问 > print("mytable 索引为 wow 的元素是 ", mytable["wow"]) > > mytable = nil > print("mytable 是 ", mytable) > ``` > ### 2.2. 常用的lua语法 1. 条件语句 ```lua -- 条件语句 if (布尔表达式0) then -- 布尔表达式0为true时执行该语句块 elseif (布尔表达式1) then -- 布尔表达式1为true时执行该语句块 else -- 布尔表达式0和1均为false时执行该语句块 end ``` 2. 循环语句 ```lua -- while 循环语句 while (condition) do -- statements end -- statements(循环体语句) 可以是一条或多条语句,condition(条件) 可以是任意表达式,在 condition(条件) 为 true 时执行循环体语句。 ``` ```lua -- for 循环语句 --[[ Lua 编程语言中 for 语句有两大类: 1、数值 for 循环 2、泛型 for 循环 ]] -- 1. 数值 for 循环 for var=exp1,exp2,exp3 do <执行体> end -- var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1。且for的三个表达式在循环开始前一次性求值,以后不再进行求值。比如上面的f(x)只会在循环开始前执行一次,其结果用在后面的循环中。 for i=10, 1, -1 do print(i) end -- 2. 泛型 for 循环 -- 泛型 for 循环通过一个迭代器函数来遍历所有值,类似 java 中的 foreach 语句。 a = {"one", "two", "three"} for i, v in ipairs(a) do -- 整数索引,此时table与数组一样,可通过a[1]来访问 “one” print(i, v) end b = {name="xiaoming", age=15, class=1} for k, v in pairs(b) do -- 键-值 结构 print(k, v) end ``` ```lua repeat -- statements until(condition) -- 循环条件判断语句(condition)在循环体末尾部分,所以在条件进行判断前循环体都会执行一次。如果条件判断语句(condition)为 false,循环会重新开始执行,直到条件判断语句(condition)为 true 才会停止执行。(类似于C语言的 do...while 循环) a = 5 repeat print(a) a = a + 1 until(a>10) ``` 3. 循环控制语句 ```lua -- break 语句 -- break 语句插入在循环体中,用于退出当前循环或语句,并开始脚本执行紧接着的语句。如果使用循环嵌套,break语句将停止最内层循环的执行,并开始执行的外层的循环语句。 a = 10 --[ while 循环 --] while( a < 20 ) do print("a 的值为:", a) a=a+1 if( a > 15) then --[ 使用 break 语句终止循环 --] break end end ``` ```lua -- goto 语句 -- goto 语句允许将控制流程无条件地转到被标记的语句处。 local a = 1 ::label:: print("--- goto label ---") a = a+1 if a < 3 then goto label -- a 小于 3 的时候跳转到标签 label end ``` 4. 函数定义 lua 函数定义格式如下: optional_function_scope function function_name( argument1, argument2, argument3..., argumentn) function_body return result_params_comma_separated end 解析: * optional_function_scope: 该参数是可选的制定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。 * function_name: 指定函数名称。 * argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。 * function_body: 函数体,函数中需要执行的代码语句块。 * result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。 示例: ```lua --[ 普通函数:返回两个数的最大值 ] function max(a, b) if (a > b) then result = a else result = b end return result end --[ 函数作为参数:求两数和,并打印最大值 ] function add(a, b, func) result = a + b print("the max number is: "..tostring(func(a, b))) return result end sum = add(2, 5, max) -- [ 多个返回值:求数组中最大值及其索引 ] function maximum (a) local mi = 1 -- 最大值索引 local m = a[mi] -- 最大值 for i,val in ipairs(a) do if val > m then mi = i m = val end end return m, mi end max_num, max_ind = maximum({8, 2, 3, 15, 7, 1}) -- [ 可变参函数:求一组整数的和 ] function add(...) local s = 0 -- 通过 select("#", ...) 获取可变参数的数量 print("arg number: "..tostring(select("#", ...))) -- {...} 表示一个由所有变长参数构成的数组 for i, v in ipairs{...} do s = s + v end return s end ``` 5. 模块和包 Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。以下为创建自定义模块 module.lua,文件代码格式如下: ```lua -- 文件名为 module.lua -- 定义一个名为 module 的模块 module = {} -- 定义一个常量 module.constant = "这是一个常量" -- 定义一个函数 function module.func1() io.write("这是一个公有函数!\n") end local function func2() print("这是一个私有函数!") end function module.func3() func2() end return module ``` ### 2.3. br28 lua库 |名称|描述|例如| |:-----:|:-----|:-----| |gui|gui 的各种控件接口|控件显示、隐藏、高亮等| |bt|蓝牙相关控制接口|蓝牙开关、搜索、连接等| |music|音乐相关控制接口|音乐开关、音量控制等| |bsp|核心资源接口|gpio、定时器、事件注册等| |device|传感器控制接口|心率、计步传感器等| ## 3. 扩展lua库 ### 3.1 SDK添加lua扩展接口和库代码     lua代码和SDK C代码之间交互通过lua虚拟机的虚拟栈实现,lua虚拟栈与普通栈一样具有先进后出的特点,C代码可以通过索引获取lua栈中的元素。lua栈的索引可以为正数或负数,正数索引“1”永远表示栈底,从栈底到栈顶依次递增。负数索引“-1”永远表示栈顶,从栈顶到栈底依次递减。
    lua的全局变量存放在一个称为全局变量表的数据结构中,lua的全局表可以想象成一个map哈希表结构,比如lua代码有一个变量:name=”hello world”,全局变量表中存放了name和“hello world”的对应关系,可以通过name在全局中找到对应的“hello world”。
1. C把name放到堆栈(栈顶),方便lua获取; 2. Lua从堆栈(栈顶)获取到name的值,获取后栈顶变为空; 3. Lua去全局表中查找name对应的字符串; 4. 全局表返回对应的字符串“hello world”; 5. Lua再次把“hello world”放到堆栈(栈顶); 6. C从堆栈(栈顶)获取name的值“hello world”。 #### 3.1.1 常用的lua CAPI 1. 常用lua虚拟栈数据操作(lua和C交互接口) |数据类型|出栈|入栈|类型判断| |:-----:|:-----|:-----|:-----| |整形|lua_tointer(L, index)|lua_pushinterger(L, num)|lua_isinterger(L, index)| |字符串|lua_tostring(L, index)|lua_pushstring(L, num)|lua_isstring(L, index)| |布尔值|lua_toboolean(L, index)|lua_pushboolean(L, num)|lua_isboolean(L, index)| |浮点数|lua_tounmber(L, index)|lua_pushnumber(L, num)|lua_isnumber(L, index)| #### 3.1.2 br28 SDK用C语言添加一个lua库 br28 lua库代码在SDK中的路径为: > apps/watch/ui/lua_ui/ 其中核心文件主要有三个,分别为 lua_module.c, lua_module.h, lua_main.lua * lua_module.c:lua解释器初始化,库加载和lua源码执行接口; * lua_module.h:各模块声明和lua库全局变量定义; * lua_main.lua:gui库的核心lua程序,创建gui库,并继承C实现的ui库,同时创建控件实例时负责调用接口加载对于控件类型的方法。 下面以utils库为例,演示实现添加一个lua库的过程 1. 新建文件 lua_utils.c和头文件lua_utils.h。头文件lua_utils.h暂时为空,在 lua_utils.c 文件中添加以下内容: ```c // lua_utils.h #ifndef __LUA_UTILS_H__ #define __LUA_UTILS_H__ #endif // lua_utils.c #include "lua/lauxlib.h" #include "lua/lualib.h" #include "lua_module.h" #include "lua_utils.h" static int utils_help(lua_State *L) { printf(">>> lua help!\n"); return 0; } // utils module const luaL_Reg utils_method[] = { {"help", utils_help}, {NULL, NULL} // 必须以null结尾 }; // 注册utils模块 LUALIB_API int luaopen_utils(lua_State *L) { luaL_newlib(L, utils_method); return 1; } ``` 2. 在 lua_module.h 中添加 utils 库注册接口定义 ```c // lua_module.h // utils模块 #define LUA_UTILSNAME "utils" LUALIB_API int (luaopen_utils)(lua_State *L); ``` 3. 在 lua_module.c 中的库列表中添加 utils 库的注册 ```c const luaL_Reg loadedlibs[] = { // 内部基本库,修改会影响使用 {"_G", luaopen_base}, {LUA_STRLIBNAME, luaopen_string}, // 添加用户自定义库 {LUA_UTILSNAME, luaopen_utils }, // utils // 必须以NULL结尾 {NULL, NULL} }; ``` 以上,便完成在lua上添加一个utils库,并在库中实现了“help”方法。启动lua解释器后,便可通过命令来调用 help 方法: > utils:help() #### 3.1.3 br28 lua库结构
#### 3.1.4 br28 gui库结构
### 3.2 模拟器添加lua扩展模拟接口     与SDK添加lua库不同,模拟器使用的lua库为通过lua源码将lua模拟器提供的ui控件操作方法进行再封装,封装成与SDK中lua库名称、参数、效果一致的方法,以此来实现模拟器模拟小机上运行效果。 ## 4. 使用lua模拟UI效果     下面以button控件高亮和非高亮状态切换为例演示在ui工具中开发APP并使用lua模拟器模拟在br28机器上运行效果的流程。 ### 4.1 创建button控件      在ui工具中新建一个页面,页面中分别添加一个图层,一个布局,在布局内添加一个按钮控件。如下图:
     创建button高亮属性,这里将高亮时背景颜色设置为黄色
### 4.2 编辑lua代码      在属性栏最下端有“lua脚本”按钮,单击它弹出lua脚本编辑窗口。lua脚本按事件类型调用对应代码,根据控件响应的事件种类不同,提供的事件类型选项也不同,例如“数字”控件只有ONLOAD和UNLOAD事件,不响应touch事件。 事件 | 备注 ---|--- ONLOAD | 控件加载,控件初始化后会调用这里的脚本,一些控件的全局变量可在这里声明。 UNLOAD | 控件释放,控件的资源释放前会调用该脚本,全局变量等控件自己使用的资源可在这里释放。 TOUCH_DOWN | touch down事件,控件被按下时调用。 TOUCH_MOVE | touch move事件,控件内滑动时(不管方向)调用。 TOUCH_R_MOVE | touch move right事件,控件内右滑时调用。 TOUCH_L_MOVE | touch move left事件,控件内左滑时调用。 TOUCH_D_MOVE | touch move down事件,控件内下滑时调用。 TOUCH_U_MOVE | touch move up事件,控件内上滑时调用。 TOUCH_HOLD | touch hold事件,控件长按时被调用。 TOUCH_UP | touch up事件,控件被松开时调用。      这里只演示按钮的高亮和非高亮状态切换,在lua脚本编辑窗口的onload和touch_up事件选项内分别添加如下代码: 1. 在ONLOAD事件中声明highlight标志变量 ```lua -- ONLOAD event print('button onload') highlight = false ``` 2. 在TOUCH_UP中添加高亮切换逻辑 ```lua button = gui:getComponentByName('BaseForm_792') if (highlight) then button:noHighLight() highlight = false else button:highLight() highlight = true end print('button highlight state: '..tostring(highlight)) button = nil ``` 3. 完成后点击“确定”保存lua脚本
### 4.3 启动模拟器 保存工程后打开模拟器,即可对以上添加的脚本响应进行仿真模拟,测试是否达到所需的效果。 1. 打开模拟器
1. 在工程目录下双击选择工程源文件,并启动模拟器
1. 运行后弹出模拟器窗口,在模拟器窗口中可模拟ui在小机中的动作及响应。若响应效果不如预期,则根据控制台打印debug。
注意:需特别留意 [ ERROR ] 的打印,系统将参数检查等内容在做在虚拟机中,如果参数类型错误等会打印相应的 [ ERROR ] 信息。小机运行时不检查参数类型,因此如果参数类型错误等会导致小机获取到的参数为空,从而不能正常运行出结果。 ### 4.4 小机运行验证 通过4.3在lua模拟器中验证完成所需功能后,将UI资源保存编译,然后下载到小机上进行最终验证。 1. 打开UI资源生成工具,一般目录为: > UI工程\ui_240x240_watch\模式界面\step2-打开UI资源生成工具.bat 2. 点击“生成资源文件”,将UI源文件编译成UI资源; 3. 通过tools目录下的“download.bat”脚本将资源文件下载到小机; 4. 运行验证。 ## 5 现有的lua接口 所有ui控件相关操作均通过 gui:getComponentByName("BUTTON_1") 这种方法获取,其中参数为UI工具中控件的唯一名称“ID号”;获取实例后系统会自动根据不同的控件类型加载对应控件的方法。其中公共方法所有控件均可使用,Text 方法只可用于文本控件,image 方法只可用于图片控件等。如果图片控件调用文本控件的方法,则系统会提示调用nil值。 ### 5.1 GUI 库 #### 5.1.1 函数接口介绍模板 1. 名称: 2. 功能: 3. 参数: 1. 无 4. 返回值: 1. 无 5. 异常情况: 1. 6. 示例: ```lua ``` #### 5.1.1 获取控件对象 1. 名称:obj = gui:getComponentByName(ename) 2. 功能:通过控件名称创建该控件的对象 3. 参数: 1. ename 编辑器中控件的名称 4. 返回值: 1. obj 控件对象 5. 异常情况: 1. 控件类型未知时,返回值obj为空 6. 示例: ```lua -- 文本控件名称 TEST_TEXT,获取该文本控件对象,并设置该文本控件显示"hello" test_text = gui:getComponentByName("TEST_TEXT") test_text:setText("hello") ``` #### 5.1.2 页面切换 1. 名称:gui:switchPageByName(ename, mode, record) 2. 功能:以指定方式跳转到指定页面,并选择是否记录跳转路径 3. 参数: 1. ename: 目标页面名称 1. "PAGE_x" 第x页的页面名称 2. mode:切换方式, 1. "left" 目标页面从左边滑入 2. "right" 目标页面从右边滑入 3. "hide" 直接刷入目标页面,无切换效果 3. record: 跳转记录标记 1. true 记录跳转路径 2. false 不记录跳转路径 4. 返回值: 1. 无 5. 异常时: 1. 跳转记录最多8层,如果跳转路径记录已满,则清除最前面的记录,后面继续追加当前记录。这将导致过多层级跳转后不能回到最开始记录的页面。 6. 示例: ```lua -- 从当前页跳转到 PAGE_1,左边滑入,记录路径,PAGE_1中可用backToPreviousPage方法回到当前页面 gui:switchPageByName("PAGE_1", "left") -- 从当前页跳转到 PAGE_3,直接刷入目标页,不记录路径 gui:switchPageByName("PAGE_3", "hide", false) ``` #### 5.1.3 返回上一页 1. 名称:gui:backToPreviousPage(mode) 2. 功能:返回记录中的上一层页面 3. 参数: 1. mode 切换模式 1. "left" 上一层页面从左边滑入 2. "right" 上一层页面从右边滑入 3. "hide" 直接刷入上一层页面,无切换效果 4. 返回值: 1. 无 5. 异常情况: 1. 无上一层页面可返回时,返回滑动列表中的第一个页面 6. 示例: ```lua -- 返回上一层页面,上一层页面从右边滑入 gui:backToPreviousPage("right") ``` #### 5.1.4 检查上一层页面 1. 名称:bool = gui:checkPreViousPage(ename) 2. 功能:检查页面跳转记录中的上一个页面是否为指定页面 3. 参数: 1. ename 页面的名称“PAGE_x” 4. 返回值: 1. bool 是否为指定页面 1. true 是指定页面 2. false 不是指定页面 5. 异常情况: 1. 无 6. 示例: ```lua -- 如果上一个页面是PAGE_3,则跳转到PAGE_5,否则跳转到PAGE_7 if (gui:checkPreviousPage("PAGE_3")) then gui:switchPageByName("PAGE_5", "hide") else gui:switchPageByName("PAGE_7", "hide") end ```