脚本UI界面
静态UI
用户可以通过在脚本中定义一个全局变量UI来实现定义脚本的配置界面, 该界面会在脚本选定时显示给用户, 用于让用户设置一些脚本的参数, 这些参数的值会赋值给指定的变量, 脚本运行时可以通过访问这些变量来获取用户的配置。下面是一个完整的例子:
UI = {
{ 'TextView{-请如实填写哦-}' },
{ 'InputBox{}', 'ui_user', '用户:'},
{ 'InputBox{}', 'ui_pass', '密码:', {type = "password"}},
{ 'InputBox{18}', 'age', '年龄:' },
{ 'DropList{是|否}', 'married', '婚否:' },
};
function main()
if not ui_user or not ui_pass or not age or not married then
sys.dialog("请先选定脚本,配置UI");
return false
end
sys.dialog(string.format("用户:%s\n密码:%s\n年龄:%s\n婚否:%s", ui_user, ui_pass, age, married));
end
上述脚本点击选定会显示一个如下界面:
用户设定完保存配置并选定脚本后,脚本运行时可以通过访问这些变量来获取用户的配置
全局变量UI是一个Table类型的变量, 其中包含若干个子Table, 每一个子Table都是一个界面上的控件, 控件按照顺序自上而下排列, 目前支持3中类型的控件:
1. TextView (静态文本)
1.1 控件说明
该类型的控件只用来显示一行文字, 不需要用户操作
1.2 控件定义
{ 'TextView{显示的内容}' }
这个Table只有一个字符串成员, 即'TextView{显示的内容}'
其中的TextView是指定此控件的类型为静态文本, {}中的内容即为该静态文本显示的内容
2. InputBox (输入框)
2.1 控件说明
该类型的控件可以用于让用户输入一些内容, 并可以指定一个变量名, 脚本开始后通过该变量就可以访问到用户输入的内容
2.2 控件定义
{ 'InputBox{默认值}', 'var', '注释', '设置' }
这个Table中有4个字符串成员:
'InputBox{默认值}', 其中的InputBox是指定此控件的类型为输入框, {}中的内容是该输入框中的默认值
'var', 定义一个变量的名字, 脚本开始后可以通过访问这个变量来获取用户输入的内容
'注释', 显示在输入框上方, 用于说明该输入框的用途
'设置', 非必填选项,填入{type = "password"}可使输入内容以*显示
2.3 使用提示
需要注意的是获取到的变量的值是默认是字符串类型, 你可以使用tonumber()函数来转换成数字类型来使用。例如
var = tonumber(var);
3. DropList (下拉列表)
3.1 控件说明
该类型的控件可以用于让用户在指定的若干个值中选择其中一个, 并可以指定一个变量名, 脚本开始后通过该变量就可以访问到用户选择的内容
3.2 控件定义
{ 'DropList{选项1|选项2|选项3|...}', 'var', '注释' }
这个Table中有3个字符串成员:
'DropList{选项1|选项2|选项3|...}', 其中的DropList是指定此控件的类型为下拉列表, {}中的内容是指定的若干个选项, 每个选项间用|分隔
'var', 定义一个变量的名字, 脚本开始后可以通过访问这个变量来获取用户选择的内容
'注释', 显示在下拉列表上方, 用于说明该下拉列表的用途
动态UI
动态UI允许用户在脚本运行当中弹出一个UI框做交互.
动态UI使用的是HTML文件,需要有HTML JS CSS语言基础.
动态UI可使用的任何CSS框架,在HTML文件中引入框架文件即可.
触摸自带了Bootstrap5框架,Bootstrap文档请看:https://v5.bootcss.com
由于使用了HTML文件,脚本需使用tep或者tepe的项目格式.
函数:sys.ui.show() 弹出UI
函数说明 : 弹出一个动态UI框
函数方法 : sys.ui.show(路径 path, 左上角坐标x?, 左上角坐标y?, 右下角坐标x?, 右下角坐标y?);
返回值 : json
适用版本 : 6.2.0以上
参数 | 类型 | 说明 | 必填 |
---|---|---|---|
path | string | 弹出的动态UI路径 | 必填 |
ltx | number | 动态UI左上角的X坐标 | 非必填,默认全屏 |
lty | number | 动态UI左上角的Y坐标 | 非必填,默认全屏 |
rbx | number | 动态UI右下角的X坐标 | 非必填,默认全屏 |
rby | number | 动态UI右下角的Y坐标 | 非必填,默认全屏 |
返回值 | 类型 | 说明 |
---|---|---|
res | json | 返回的UI数据 |
示例:
function main()
--脚本未项目格式首先要获取项目路径
wd = script.workingDir()
--弹出项目脚本res文件夹内的index.html UI
res = sys.ui.show(wd .. "/res/index.html",100,100,500,300)
--res为UI的返回值,例如 {"type":"ok","data":{"input":"touchelf"}}
sys.log(res)
end
教程示例下载地址:https://share.weiyun.com/4hvVPhBm
教程:弹出一个确认框
本教程演示功能:
弹出一个确认框
通过返回值判断脚本是否继续
main.lua :
function main()
wd = script.workingDir()
res = sys.ui.show(wd .. "/res/alert.html",100,100,500,300)
--返回数据{"type":"ok"}
res = codec.json.decode(res)
if res.type == "ok" then
--脚本继续
elseif res.type == "cancel" then
--脚本停止
script.stop();
end
end
alert.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
</head>
<body>
<!-- 提示语句 -->
<h3>是否继续</h3>
<!-- 按钮区域,此处必须写,否则无法关闭动态UI-->
<div style="padding-top: 10px">
<!-- onOk()和onCancel()需要和JS内的function onOk() function onCancel()对应 -->
<button onclick="onOk()">确定</button>
<button onclick="onCancel()">取消</button>
</div>
<script>
function onOk() {
// touchelf.return()为触摸内置函数, 此函数将关闭UI, 并将数据发送给sys.ui.show(), 作为其返回值
touchelf.return(JSON.stringify({ type: "ok" }));
}
function onCancel() {
touchelf.return(JSON.stringify({ type: "cancel" }));
}
</script>
</body>
</html>
教程:弹出一个输入框并保存配置
本教程演示功能:
UI中加载本地图片
UI中增加输入框
保存,读取UI中的设置
脚本输出动态UI中输入框内容
main.lua :
function main()
wd = script.workingDir()
--截图用作动态UI里面显示
screen.snapshot("/var/touchelf/a.png", 100, 100, 200, 200)
res = sys.ui.show(wd .. "/res/input.html",100,100,500,500)
--返回数据{"type":"ok","data":{"input":"touchelf"}}
res = codec.json.decode(res)
if res.type == "ok" then
--脚本继续
sys.log(res.data.input)
elseif res.type == "cancel" then
--脚本停止
script.stop();
end
end
input.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
</head>
<body>
<!-- 加载本地图片 -->
<img src="file:///var/touchelf/a.png"/>
<!-- 输入框 id内的input名字随意修改-->
<input id="input" type="text" />
<!-- 按钮区域,此处必须写,否则无法关闭动态UI-->
<div style="padding-top: 10px">
<!-- onOk()和onCancel()需要和JS内的function onOk() function onCancel()对应 -->
<button onclick="onOk()">确定</button>
<button onclick="onCancel()">取消</button>
</div>
<script>
// 定义一个变量,名字随意,请勿重复
var SAVE_KEY = "uitest";
// 加载上次保存的设置到界面
window.onload = function() {
var data = localStorage.getItem(SAVE_KEY);
if (data) {
var obj = JSON.parse(data);
// input跟输入框内的id相对应,多个配置在下面添加
// 例如:
// document.getElementById("input2").value = obj.input2;
//document.getElementById("select").value = obj.select;
document.getElementById("input").value = obj.input;
}
};
function onOk() {
// 获取输入框内的值
var data = {
input: document.getElementById("input").value,
};
// 保存设置以供下次加载
localStorage.setItem(SAVE_KEY, JSON.stringify(data));
// touchelf.return()为触摸内置函数, 此函数将关闭UI, 并将数据发送给sys.ui.show(), 作为其返回值
touchelf.return(
JSON.stringify({
type: "ok",
data: data,
})
);
}
function onCancel() {
touchelf.return(JSON.stringify({ type: "cancel" }));
}
</script>
</body>
</html>
教程:加载UI框架美化动态UI
本教程演示功能:
加载UI框架
UI中增加各种常用组件
脚本输出动态UI中各种组件内容
效果展示:
main.lua :
function main()
wd = script.workingDir()
res = sys.ui.show(wd .. "/res/ui.html")
sys.log(res)
end
ui.html :
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<!-- 加载UI框架 (也可以从网络加载你熟悉的任何框架)-->
<!-- IOS路径 -->
<link
href="file:///var/touchelf/var/res/www/bootstrap/bootstrap.min.css"
rel="stylesheet"
/>
<!-- 安卓路径
<link
href="file:///mnt/sdcard/touchelf/var/res/www/bootstrap/bootstrap.min.css"
rel="stylesheet"
/>
-->
</head>
<body>
<div class="shadow-sm p-3 mb-5 bg-white rounded">
<h4>脚本配置</h4>
<!-- 输入框 -->
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm">输入</span>
<input id="input" type="text" class="form-control" />
</div>
<!-- 下拉框 -->
<select id="select" class="form-select">
<option selected>下拉菜单</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<!-- 复选框 -->
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="Checkbox1" value="option1">
<label class="form-check-label" for="inlineCheckbox1">复选1</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="Checkbox2" value="option2">
<label class="form-check-label" for="inlineCheckbox2">复选2</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="Checkbox3" value="option3" disabled>
<label class="form-check-label" for="inlineCheckbox3">复选3 (禁止选择)</label>
</div>
<!-- 范围条 -->
<input id="range" type="range" class="form-range" />
<!-- 单选框 -->
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="Radio1" value="option1" checked>
<label class="form-check-label" for="inlineRadio1">单选1 (默认选择)</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="Radio2" value="option2">
<label class="form-check-label" for="inlineRadio2">单选2</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="Radio3" value="option3" disabled>
<label class="form-check-label" for="inlineRadio3">单选3 (禁止选择)</label>
</div>
<!-- 开关 -->
<div>
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
id="Switch1"
/>
<label class="form-check-label" for="flexSwitchCheckDefault"
>开关</label
>
</div>
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
id="Switch2"
checked
/>
<label class="form-check-label" for="flexSwitchCheckChecked"
>开关默认开启</label
>
</div>
</div>
<!-- 按钮 -->
<div style="padding-top: 10px">
<button type="button" class="btn btn-primary" onclick="onOk()">
确定
</button>
<button type="button" class="btn btn-danger" onclick="onCancel()">
取消
</button>
</div>
</div>
<script>
// touchelf.return()为触摸内置函数, 此函数将关闭UI, 并将数据发送给sys.ui.show(), 作为其返回值
function onOk() {
touchelf.return(
JSON.stringify({
type: "ok",
// 输入框值
input: document.getElementById("input").value,
// 选择框值
select: document.getElementById("select").value,
// 复选框值
Checkbox1: document.getElementById("Checkbox1").checked,
Checkbox2: document.getElementById("Checkbox2").checked,
Checkbox3: document.getElementById("Checkbox3").checked,
// 滑块值
range: document.getElementById("range").value,
// 单选框值
Radio1: document.getElementById("Radio1").checked,
Radio2: document.getElementById("Radio2").checked,
Radio3: document.getElementById("Radio3").checked,
// 开关值
Switch1: document.getElementById("Switch1").checked,
Switch2: document.getElementById("Switch2").checked,
})
);
}
function onCancel() {
touchelf.return(JSON.stringify({ type: "cancel" }));
}
</script>
<!-- 加载框架JS -->
<!-- IOS路径 -->
<script
src="file:///var/touchelf/var/res/www/bootstrap/bootstrap.bundle.min.js">
</script>
<!-- 安卓路径
<script
src="file:///mnt/sdcard/touchelf/var/res/www/bootstrap/bootstrap.bundle.min.js">
</script>
-->
</body>
</html>
教程:调试动态UI中JS错误
本教程演示功能:
由于JS错误会导致点击确认或取消按钮无反应,可使用下面代码调试动态UI中的JS错误,该代码遇到错误会将错误返回到触摸脚本
main.lua:
function main()
wd = script.workingDir()
res = sys.ui.show(wd .. "/res/error.html")
res = codec.json.decode(res)
if res.type == "ok" then
--脚本继续
elseif res.type == "cancel" then
--脚本停止
script.stop();
elseif res.type == "error" then
--遇到错误,返回错误内容
sys.log(res)
--[[返回数据示例
{
data = "TypeError: null is not an object (evaluating 'document.getElementById('input').value')",
type = "error"
}]]
--脚本停止
script.stop();
end
end
error.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
</head>
<body>
<!-- 提示语句 -->
<h3>返回错误</h3>
<!-- 按钮区域,此处必须写,否则无法关闭动态UI-->
<div style="padding-top: 10px">
<!-- onOk()和onCancel()需要和JS内的function onOk() function onCancel()对应 -->
<button onclick="onOk()">确定</button>
<button onclick="onCancel()">取消</button>
</div>
<script>
function onOk() {
// touchelf.return()为触摸内置函数, 此函数将关闭UI, 并将数据发送给sys.ui.show(), 作为其返回值
try{
touchelf.return(
JSON.stringify({
type: 'ok',
data: {
//这里获取一个不存在的值,会导致错误
input: document.getElementById('input').value,
},
})
)
} catch (e) {
//返回错误内容
touchelf.return(
JSON.stringify({
type: 'error',
data: e.toString(),
})
)
}
}
function onCancel() {
touchelf.return(JSON.stringify({ type: "cancel" }));
}
</script>
</body>
</html>
常见问题
确认取消按钮点击无反应:
按钮点击无反应可能存在以下问题
1.HTML页面内的JS代码错误.
2.低版本系统(ios10 以下)不支持es6语法,改用es5语法编写JS
select选择框问题:
由于select选择框调用的是系统的原生选择框,各别系统下无法正常弹出,可尝试先点击下输入框弹出输入法后在点击选择框.
如以上方案不能解决则可以使用下面代码替换原生select选择框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 使用select2库解决原生select不能弹出选择框的问题 -->
<link
href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<!-- 以上文件可以自行下载后打包在脚本内,然后使用本地文件的加载方式,避免每次从网络加载耗费流量-->
</head>
<body>
<select id="select" style="width: 100%">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<div style="padding-top: 10px">
<button onclick="onOk()">确定</button>
<button onclick="onCancel()">取消</button>
</div>
<script>
$(document).ready(function () {
// 转换所有select标签
$("select").select2();
});
function onOk() {
touchelf.return(
JSON.stringify({
type: "ok",
data: {
select: document.getElementById("select").value,
},
})
);
}
function onCancel() {
touchelf.return(JSON.stringify({ type: "cancel" }));
}
</script>
</body>
</html>