"ui";
// 显示控制台的悬浮窗
console.show();
// 隐藏输入框和确定按钮
ui.run(function() {
let mConsoleViewField = runtime.console.getClass().getDeclaredField('mConsoleView');
mConsoleViewField.setAccessible(true);
let refConsoleView = mConsoleViewField.get(runtime.console);
let mConsoleView = refConsoleView.get();
mConsoleView.findViewById(com.stardust.autojs.R.id.input_container).visibility = android.view.View.GONE;
});
/**

  • 显示配置对话框 - 优化版
    */
    function showConfigDialog() {

    try {
    log("在UI线程中显示配置对话框");
    // 创建一个自定义布局的对话框
    var d = dialogs.build({
    title: "请选择并输入",
    view: ui.layout(
    <vertical padding="16">
    <!-- 文本输入框 -->
    <text text="请输入内容:" marginBottom="8" />
    <edittext id="inputText" hint="在此输入文本..." marginBottom="16" />

                 <!-- 单选框组 -->
                 <text text="请选择一项:" marginBottom="8" />
                 <radiogroup id="radioGroup" orientation="vertical">
                     <radiobutton text="选项A1" id="optionA1" />
                     <radiobutton text="选项B1" id="optionB1" />
                     <radiobutton text="选项C1" id="optionC1" />
                     <radiobutton text="选项D1" id="optionD1" />
                 </radiogroup>
             </vertical>
         ),
         positive: "确定",
         negative: "取消",
         onPositive: function() {
             // 获取文本输入框的值
             var inputValue = d.getView().findViewById("inputText").getText();
    
             // 获取选中的单选框的值
             var radioGroup = d.getView().findViewById("radioGroup");
             var checkedId = radioGroup.getCheckedRadioButtonId();
             var selectedOption = "";
    
             if (checkedId != -1) {
                 var radioButton = d.getView().findViewById(checkedId);
                 selectedOption = radioButton.getText();
             }
    
             // 显示结果
             toast("输入内容: " + inputValue + "\n选择选项: " + selectedOption);
         }
     });
    
     // 显示对话框
     d.show()
    

    } catch (e) {
    log("显示配置对话框时出错: " + e.message);
    }
    }

/**

  • 主函数
    */
    function main() {
    // 检查无障碍服务是否开启
    if (!auto.service) {
    log("无障碍服务未开启,请先开启");
    auto.waitFor();
    return;
    }

    // 创建悬浮窗
    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);

    // 开始运行脚本
    floatyWin.startBtn.click(function() {
    log("开始执行脚本...");
    });

    // 配置按钮 - 在UI线程中显示配置对话框
    floatyWin.configBtn.click(function() {
    log("打开配置界面...");
    showConfigDialog();
    });

    // 退出按钮
    floatyWin.exitBtn.click(function() {
    log("退出脚本");
    floatyWin.close();
    hamibot.exit();
    });

    // 保持悬浮窗不被关闭
    setInterval(function() {}, 1000);
    }

// 执行主函数
main();

为什么最上层只要加上"ui"; 脚本运行页面就无法正常加载卡死,不加"ui";就会提示ui.layout需要再ui模式下运行才能使用

已存档
七月CX · 2 个月前
第 1 条补充
·
2 个月前

<vertical padding="16">
<!-- 文本输入框 -->
<text text="请输入内容:" marginBottom="8" />
<edittext id="inputText" hint="在此输入文本..." marginBottom="16" />

                <!-- 单选框组 -->
                <text text="请选择一项:" marginBottom="8" />
                <radiogroup id="radioGroup" orientation="vertical">
                    <radiobutton text="选项A1" id="optionA1" />
                    <radiobutton text="选项B1" id="optionB1" />
                    <radiobutton text="选项C1" id="optionC1" />
                    <radiobutton text="选项D1" id="optionD1" />
                </radiogroup>
            </vertical>  那住部分代码用ui.run该怎么写
第 2 条补充
·
2 个月前

问题2中你给的场景2中,虽然不需要用到"ui";,但你仍然使用了ui.layout,不还是会造成冲突么,这并没有解决我说的问题

回答

Hamibot AI
1
· 2 个月前

这个问题是因为在脚本中同时使用了两种不同的UI模式(模块模式和非模块模式)导致的冲突。我来解释原因和解决方案:

原因分析:

  1. "ui";声明会导致脚本进入模块模式(module mode),此时所有UI操作都必须在ui.run()里执行
  2. 你代码中的ui.layout()floaty.window()等操作都在主线程直接调用,与模块模式的要求冲突

解决方案(二选一):

方法一:移除"ui";声明,保持非模块模式(推荐)

// 文档地址 https://docs.hamibot.com/
// 直接使用非模块模式

// 显示控制台的悬浮窗
console.show();
// 隐藏输入框和确定按钮
ui.run(function() {
  let mConsoleViewField = runtime.console.getClass().getDeclaredField('mConsoleView');
  mConsoleViewField.setAccessible(true);
  let refConsoleView = mConsoleViewField.get(runtime.console);
  let mConsoleView = refConsoleView.get();
  mConsoleView.findViewById(com.stardust.autojs.R.id.input_container).visibility = android.view.View.GONE;
});

// 剩下的代码保持不变
// ...
hamibot.exit();

方法二:保持"ui";声明,将所有UI操作放入ui.run()

"ui";
// 文档地址 https://docs.hamibot.com/

// 显示控制台的悬浮窗
console.show();
// 隐藏输入框和确定按钮
ui.run(function() {
  let mConsoleViewField = runtime.console.getClass().getDeclaredField('mConsoleView');
  mConsoleViewField.setAccessible(true);
  let refConsoleView = mConsoleViewField.get(runtime.console);
  let mConsoleView = refConsoleView.get();
  mConsoleView.findViewById(com.stardust.autojs.R.id.input_container).visibility = android.view.View.GONE;
  
  // 将主函数中的所有UI操作移到这里
  main();
});

function main() {
  // 所有UI操作代码...
}
hamibot.exit();

关键区别:

  • 非模块模式更灵活,可以直接在主线程调用UI操作
  • 模块模式更严格,所有UI操作必须在ui.run()中执行

建议使用第一种方案(移除"ui";),因为你的脚本中已经使用了ui.run()来处理需要UI线程的部分,这样能保持代码结构更清晰。


补充回答 1

要将这部分XML布局代码用ui.run包装,可以采用以下方式。这里有两种常见场景的写法:

场景1:在对话框中使用(如原代码示例)

// 文档地址 https://docs.hamibot.com/

var dialogView = ui.run(function() {
    return ui.layout(
        <vertical padding="16">
            <!-- 文本输入框 -->
            <text text="请输入内容:" marginBottom="8" />
            <edittext id="inputText" hint="在此输入文本..." marginBottom="16" />

            <!-- 单选框组 -->
            <text text="请选择一项:" marginBottom="8" />
            <radiogroup id="radioGroup" orientation="vertical">
                <radiobutton text="选项A1" id="optionA1" />
                <radiobutton text="选项B1" id="optionB1" />
                <radiobutton text="选项C1" id="optionC1" />
                <radiobutton text="选项D1" id="optionD1" />
            </radiogroup>
        </vertical>
    );
});

// 然后在对话框中引用这个View
var d = dialogs.build({
    title: "请选择并输入",
    view: dialogView,
    positive: "确定",
    negative: "取消",
    // 其他回调...
});
d.show();

场景2:直接作为主界面使用

"ui";
// 文档地址 https://docs.hamibot.com/

ui.run(function() {
    ui.layout(
        <vertical padding="16">
            <!-- 文本输入框 -->
            <text text="请输入内容:" marginBottom="8" />
            <edittext id="inputText" hint="在此输入文本..." marginBottom="16" />

            <!-- 单选框组 -->
            <text text="请选择一项:" marginBottom="8" />
            <radiogroup id="radioGroup" orientation="vertical">
                <radiobutton text="选项A1" id="optionA1" />
                <radiobutton text="选项B1" id="optionB1" />
                <radiobutton text="选项C1" id="optionC1" />
                <radiobutton text="选项D1" id="optionD1" />
            </radiogroup>
        </vertical>
    );
    
    // 可以在这里添加控件事件处理
    ui.inputText.on("key", function(event) {
        if(event.action == KeyEvent.ACTION_UP && event.keyCode == KeyEvent.KEYCODE_ENTER) {
            toast("你输入了: " + ui.inputText.getText());
        }
    });
});

// 保持脚本运行
setInterval(function(){}, 1000);
hamibot.exit();

关键要点:

  1. 如果使用"ui";声明,则所有UI操作(包括ui.layout())必须在ui.run()中执行
  2. 如果作为对话框内容使用,可以先用ui.run生成View对象,再传递给对话框
  3. 事件绑定也应该在ui.run中进行

注意:在实际使用中,更推荐第一种方式(非模块模式),除非你确实需要使用模块模式的特定功能。


补充回答 2

你说得对,确实我在场景2的处理方式上存在矛盾。让我们再重新梳理这个问题,并给出完全正确的解决方案。

问题的本质

  1. 冲突原因:当使用 "ui"; 声明时,整个脚本会进入模块模式,此时 所有UI操作(包括ui.layout和控件访问)都 必须ui.run() 中执行
  2. 你的需求:既想使用ui.layout,又不想因为"ui";导致脚本卡死

完全正确的解决方案(三种写法)

方案1:完全不使用 "ui";(推荐)

// 文档地址 https://docs.hamibot.com/

// 直接使用ui.layout(非模块模式)
var layout = ui.layout(
    <vertical padding="16">
        <text text="请输入内容:" marginBottom="8" />
        <edittext id="inputText" hint="在此输入文本..." marginBottom="16" />
        <radiogroup id="radioGroup" orientation="vertical">
            <radiobutton text="选项A1" id="optionA1" />
            <radiobutton text="选项B1" id="optionB1" />
            <radiobutton text="选项C1" id="optionC1" />
            <radiobutton text="选项D1" id="optionD1" />
        </radiogroup>
    </vertical>
);

// 控件操作也不需要ui.run
ui.inputText.setText("默认文本"); 

// 保持运行
setInterval(function(){}, 1000);
hamibot.exit();

方案2:使用 "ui"; 但正确封装(适用于复杂UI)

"ui";
// 文档地址 https://docs.hamibot.com/

ui.run(function(){
    // 所有UI操作必须在这里面
    ui.layout(
        <vertical padding="16">
            <text text="请输入内容:" marginBottom="8" />
            <edittext id="inputText" hint="在此输入文本..." marginBottom="16" />
            <radiogroup id="radioGroup" orientation="vertical">
                <radiobutton text="选项A1" id="optionA1" />
                <radiobutton text="选项B1" id="optionB1" />
                <radiobutton text="选项C1" id="optionC1" />
                <radiobutton text="选项D1" id="optionD1" />
            </radiogroup>
        </vertical>
    );
    
    // 事件绑定也在这里
    ui.inputText.on("key", function(e){
        if(e.keyCode == 66){ // 回车键
            toast(ui.inputText.getText());
        }
    });
});

// 非UI操作可以放在外面
log("界面已加载");
hamibot.exit();

方案3:对话框场景专用写法(不需要模块声明)

// 文档地址 https://docs.hamibot.com/

// 直接创建布局(不需要ui.run)
var view = ui.layout(
    <vertical padding="16">
        <!-- 你的布局内容 -->
    </vertical>
);

// 用于对话框
dialogs.build({
    title: "配置",
    view: view,
    positive: "确定",
    negative: "取消"
}).show();

hamibot.exit();

使用建议

  1. 简单脚本:用方案1(不声明"ui";
  2. 复杂UI交互:用方案2(声明"ui";并严格封装)
  3. 对话框使用:用方案3(最简洁)

特别说明:当不使用"ui";时,ui.layout和控件访问可以直接执行,这是完全合法的用法,不会造成冲突。只有在使用"ui";声明后,才需要严格遵守ui.run的封装要求。

ℹ️ 本回答由 AI 生成,内容仅供参考