function showConfigDialog() {
try {
log("在UI线程中显示配置对话框");
// 在UI线程中构建并显示对话框
ui.run(function() {
// 构建对话框
var dialog = dialogs.build({
title: "脚本配置",
view: ui.layout(
<vertical padding="16">
<text textSize="16sp" textStyle="bold" marginBottom="10">基本设置</text>
<linear gravity="center_vertical" marginBottom="10">
<text text="调试模式:" width="100" />
<switch id="debugSwitch" checked={config.debugMode} />
</linear>
<linear gravity="center_vertical" marginBottom="10">
<text text="操作延迟:" width="100" />
<numberpicker id="delayPicker" minValue="500" maxValue="3000" value={config.waitTime.operation/100} layout_weight="1" />
<text text="毫秒" marginLeft="5" />
</linear>
<linear gravity="center_vertical" marginBottom="10">
<text text="循环间隔:" width="100" />
<numberpicker id="loopPicker" minValue="500" maxValue="2000" value={config.waitTime.loopInterval/100} layout_weight="1" />
<text text="毫秒" marginLeft="5" />
</linear>
<linear gravity="center_vertical" marginBottom="10">
<text text="最大重试次数:" width="100" />
<numberpicker id="retryPicker" minValue="1" maxValue="10" value={config.waitTime.maxRetry} layout_weight="1" />
</linear>
</vertical>
),
positive: "确定",
negative: "取消"
});
// 显示对话框并处理结果
var result = dialog.show();
if (result) {
// 直接更新配置,因为已经在UI线程中
config.debugMode = ui.debugSwitch.checked();
config.waitTime.operation = ui.delayPicker.value() * 100;
config.waitTime.loopInterval = ui.loopPicker.value() * 100;
config.waitTime.maxRetry = ui.retryPicker.value();
log("配置已更新");
}
});
} catch (e) {
log("显示配置对话框时出错: " + e.message);
}
} 脚本运行到这个函数后 无法正常构建UI界面 脚本就会卡死 即使在最上层写入“ui”; 也不行
按照你说的修改开头添加"ui"; 移除 ui.run, 运行后手机直接黑屏
// 创建悬浮窗
var floatyWin = floaty.window(
<vertical padding="5" backgroundColor="#33000000" gravity="center">
<horizontal spacing="0">
<button
id="startBtn"
text="开始"
width="60"
height="30"
textSize="12sp"
margin="0"
padding="2"
/>
<button
id="configBtn"
text="配置"
width="60"
height="30"
textSize="12sp"
margin="0"
padding="2"
/>
<button
id="exitBtn"
text="退出"
width="60"
height="30"
textSize="12sp"
margin="0"
padding="2"
/>
</horizontal>
</vertical>
);
// 设置悬浮窗位置
floatyWin.setPosition(device.width - 500, 100);
// 保持悬浮窗不被关闭
setInterval(function() {}, 1000); 这个悬浮窗的显示会造成与ui界面显示的冲突么
回答
这个问题的解决方案是:
- 确保在脚本开头已经正确声明了UI模式:
"ui";
- 修改对话框构建方式,避免直接在UI线程中阻塞:
// 文档地址 https://docs.hamibot.com/
function showConfigDialog() {
try {
log("显示配置对话框");
var dialog = dialogs.build({
title: "脚本配置",
view: ui.layout(
<vertical padding="16">
<text textSize="16sp" textStyle="bold" marginBottom="10">基本设置</text>
<linear gravity="center_vertical" marginBottom="10">
<text text="调试模式:" width="100" />
<switch id="debugSwitch" checked={config.debugMode} />
</linear>
<linear gravity="center_vertical" marginBottom="10">
<text text="操作延迟:" width="100" />
<numberpicker id="delayPicker" minValue="500" maxValue="3000" value={config.waitTime.operation/100} layout_weight="1" />
<text text="毫秒" marginLeft="5" />
</linear>
<linear gravity="center_vertical" marginBottom="10">
<text text="循环间隔:" width="100" />
<numberpicker id="loopPicker" minValue="500" maxValue="2000" value={config.waitTime.loopInterval/100} layout_weight="1" />
<text text="毫秒" marginLeft="5" />
</linear>
<linear gravity="center_vertical" marginBottom="10">
<text text="最大重试次数:" width="100" />
<numberpicker id="retryPicker" minValue="1" maxValue="10" value={config.waitTime.maxRetry} layout_weight="1" />
</linear>
</vertical>
),
positive: "确定",
negative: "取消"
}).on("positive", function() {
config.debugMode = ui.debugSwitch.checked();
config.waitTime.operation = ui.delayPicker.value() * 100;
config.waitTime.loopInterval = ui.loopPicker.value() * 100;
config.waitTime.maxRetry = ui.retryPicker.value();
log("配置已更新");
}).show();
} catch (e) {
log("显示配置对话框时出错: " + e.message);
}
}
hamibot.exit();
关键修改点:
- 移除ui.run()调用,直接在UI线程中执行
- 使用事件监听器而不是阻塞等待对话框结果
- 确保UI组件使用正确的方式访问
如果问题仍然存在,建议检查:
- 确保config对象已正确初始化
- 检查是否有其他脚本代码影响UI线程
- 确认设备是否支持UI模式
补充回答 1
当UI界面导致黑屏时,通常有以下几种原因和解决方案:
- UI线程阻塞问题:
"ui";
// 文档地址 https://docs.hamibot.com/
function showConfigDialog() {
dialogs.build({
title: "脚本配置",
positive: "确定",
negative: "取消",
view: ui.inflate(
<vertical padding="16">
<text textSize="16sp" textStyle="bold">基本设置</text>
<switch id="debugSwitch" text="调试模式" checked={config.debugMode}/>
<text text="操作延迟:(毫秒)"/>
<seekbar id="delaySlider" min="500" max="3000" progress={config.waitTime.operation}/>
</vertical>
)
}).on("positive", function(){
config.debugMode = ui.debugSwitch.checked();
config.waitTime.operation = ui.delaySlider.progress;
toast("配置已保存");
}).show();
}
hamibot.exit();
关键改进:
-
使用更简单的UI布局(避免复杂控件)
-
用
ui.inflate
代替ui.layout
-
改用seekbar避免numberpicker可能的问题
-
其他可能原因和解决方案:
如果仍然黑屏,请按此顺序排查:
- 检查Android权限:
if(!requestScreenCapture()){
alert("请授予屏幕截图权限");
exit();
}
- 确保在主线程调用:
"ui";
ui.post(() => {
showConfigDialog();
});
- 最小化代码测试:
"ui";
dialogs.build({
title:"测试",
content:"简单对话框测试",
positive:"确定"
}).show();
- 设备兼容性方案:
"ui";
setTimeout(function(){
showConfigDialog();
}, 500);
如果问题依旧存在,可能是:
- 系统UI兼容性问题(尝试换个设备)
- 内存不足(关闭其他应用)
- Hamibot版本问题(更新到最新版)
建议先测试最简单的对话框是否能显示,再逐步添加复杂功能。
补充回答 2
悬浮窗(floaty.window
)和普通UI界面("ui"
模式)在 Hamibot 中运行时不会产生直接的冲突,但需要注意以下几点:
✅ 不会冲突的情况
- 悬浮窗独立于UI线程
- 悬浮窗是通过系统级浮窗实现,而普通UI界面是通过Hamibot的UI线程渲染,两者属于不同的机制。
- 可同时存在
- 你可以同时显示悬浮窗和
dialogs.build()
或"ui"
模式的界面。
- 你可以同时显示悬浮窗和
⚠️ 需要注意的问题
-
触摸事件的优先级
- 悬浮窗的按钮响应可能会被UI界面的弹窗遮挡,此时需要确保悬浮窗的
setTouchable(true)
(默认已是可触摸状态)。
- 悬浮窗的按钮响应可能会被UI界面的弹窗遮挡,此时需要确保悬浮窗的
-
线程安全操作UI控件
- 如果在悬浮窗按钮的回调中修改UI界面的内容(如更改文本框文字),必须用
ui.run
包裹:
- 如果在悬浮窗按钮的回调中修改UI界面的内容(如更改文本框文字),必须用
floatyWin.configBtn.click(function() {
ui.run(() => {
dialogs.build({ title: "配置" }).show(); // 安全调用UI对话框
});
});
- 悬浮窗位置调整
- 全屏UI界面(如游戏画面)可能会遮挡悬浮窗,建议用
setPosition()
调整悬浮窗位置:
- 全屏UI界面(如游戏画面)可能会遮挡悬浮窗,建议用
floatyWin.setPosition(device.width - 200, 50); // 放在右上角
🛠 推荐代码改进
// 文档地址 https://docs.hamibot.com/
"ui"; // 仍建议声明UI模式(如果脚本有UI需求)
// 创建悬浮窗
var floatyWin = floaty.window(
<vertical bg="#33000000" gravity="center">
<horizontal>
<button id="startBtn" text="开始" w="60" h="30" textSize="12sp"/>
<button id="configBtn" text="配置" w="60" h="30" textSize="12sp"/>
<button id="exitBtn" text="退出" w="60" h="30" textSize="12sp"/>
</horizontal>
</vertical>
);
// 设置初始位置(避开系统状态栏)
floatyWin.setPosition(device.width - 180, 50);
// 按钮事件
floatyWin.exitBtn.click(() => {
floatyWin.close();
hamibot.exit();
});
floatyWin.configBtn.click(() => {
ui.run(() => {
dialogs.build({ title: "配置", positive: "确定" }).show();
});
});
// 保持脚本运行
setInterval(() => {}, 1000);
总结
- 不冲突:悬浮窗和UI界面可以共存。
- 注意事项:
- 避免悬浮窗被遮挡(调整位置)
- 在悬浮窗回调中操作UI控件时用
ui.run
- 确保悬浮窗的
setTouchable(true)
(默认已开启)
如果仍有问题,可能是设备权限限制(如未开启“悬浮窗权限”),需检查Hamibot的权限设置。