AutoJs6 中文文档 下载 App

UI 事件绑定 — click、change、touch、focus 详解

事件绑定方式

AutoJs6 提供两种事件绑定方式:便捷方法(常用事件)和 on() 方法(通用事件)。

// 方式一:便捷方法(推荐,代码简洁)
ui.myBtn.click(() => {
    // 点击处理
});

// 方式二:通用 on() 方法
ui.myBtn.on("click", () => {
    // 点击处理
});

两种方式效果相同。便捷方法本质是 on() 的语法糖。

全部事件类型

基础交互事件

事件触发时机参数便捷方法
click点击控件view✅ .click(fn)
longClick长按控件view✅ .longClick(fn)
touch触摸屏幕view, MotionEvent❌ 用 .on("touch", fn)
doubleClick双击view❌

输入控件事件

事件触发时机参数便捷方法
change控件值变化newValue✅ .on("change", fn)
focus焦点变化hasFocus✅ .on("focus", fn)
blur失去焦点-❌
textChange文本变化newText❌

滑动与选择事件

事件触发时机参数适用控件
progressChange进度变化progressseekbar, progressbar
checkedChange选中状态变化checkedcheckbox, switch
selectedChange选中项变化itemspinner

事件绑定示例

click — 点击

ui.layout(<button id="btn" text="点击我"/>);

// 无参数
ui.btn.click(() => {
    toast("被点击了");
});

// 接收 view 参数
ui.btn.click((view) => {
    console.log("点击了: " + view.id);
});

longClick — 长按

ui.layout(<button id="btn" text="长按我"/>);

ui.btn.longClick(() => {
    toast("长按触发");
});

// 长按和点击可以同时绑定
ui.btn.click(() => toast("点击"));
ui.btn.longClick(() => toast("长按"));

touch — 触摸(多点触控)

ui.layout(<vertical id="touchArea" w="*" h="300" bg="#EEE"/>);

ui.touchArea.on("touch", (view, event) => {
    let action = event.getAction();
    let x = event.getRawX();
    let y = event.getRawY();
    
    // action 类型
    // 0 = ACTION_DOWN(按下)
    // 1 = ACTION_UP(抬起)
    // 2 = ACTION_MOVE(移动)
    
    if (action === 0) {
        console.log("按下: (" + x + ", " + y + ")");
    } else if (action === 2) {
        console.log("移动到: (" + x + ", " + y + ")");
    } else if (action === 1) {
        console.log("抬起");
    }
});

change — 值变化

ui.layout(
    <vertical>
        <input id="field" hint="输入点什么"/>
        <switch id="enable" checked="false"/>
        <checkbox id="agree" text="同意"/>
        <seekbar id="slider" max="100"/>
    </vertical>
);

// 输入框内容变化
ui.field.on("change", (text) => {
    console.log("输入: " + text);
});

// 开关切换
ui.enable.on("change", (checked) => {
    console.log("开关: " + (checked ? "开" : "关"));
});

// 复选框勾选
ui.agree.on("change", (checked) => {
    console.log("同意: " + checked);
});

// 滑动条值变化
ui.slider.on("change", (progress) => {
    console.log("当前值: " + progress);
});

focus — 焦点变化

ui.layout(
    <vertical>
        <input id="name" hint="姓名"/>
        <input id="phone" hint="电话"/>
    </vertical>
);

ui.name.on("focus", (hasFocus) => {
    if (hasFocus) {
        console.log("姓名框获得焦点");
    } else {
        console.log("姓名框失去焦点");
    }
});

ui.phone.on("focus", (hasFocus) => {
    if (hasFocus) {
        console.log("电话框获得焦点");
    }
});

一次绑定多个事件

ui.layout(<button id="btn" text="多功能按钮"/>);

// 可以同时绑定多种事件
ui.btn.click(() => toast("点击"));
ui.btn.longClick(() => toast("长按"));
ui.btn.on("touch", (v, e) => {
    // 触摸事件也可以和点击共存
});

移除事件监听

v6.7 新增了部分移除监听能力:

// 保存监听函数引用
let onBtnClick = () => {
    toast("执行操作");
};

ui.btn.click(onBtnClick);

// 移除指定监听(需测试各事件是否支持)
// ui.btn.removeListener("click", onBtnClick);

如果移除方法不可用,可用"空函数覆盖"或"重建界面"替代。

防重复点击

// 简单的防抖(快速连点只触发一次)
let lastClickTime = 0;

ui.submitBtn.click(() => {
    let now = Date.now();
    if (now - lastClickTime < 1000) {
        console.log("点击过快,忽略");
        return;
    }
    lastClickTime = now;
    
    // 实际逻辑...
    toast("提交成功");
});

异步处理

// 点击事件中执行异步操作
ui.loginBtn.click(async () => {
    // 显示"登录中"状态
    ui.loginBtn.setEnabled(false);
    ui.loginBtn.setText("登录中...");
    
    try {
        let result = await api.login(email, password);
        toast("登录成功");
    } catch (err) {
        toast("登录失败: " + err.message);
    }
    
    // 恢复按钮状态
    ui.loginBtn.setEnabled(true);
    ui.loginBtn.setText("登录");
});

注意:Rhino 对 async/await 支持有限,建议用回调或 Promise 链。

实战:表单验证

"ui";

ui.layout(
    <vertical padding="16">
        <input id="username" hint="用户名(3-16位)"/>
        <input id="email" hint="邮箱地址"/>
        <input id="age" hint="年龄" inputType="number"/>
        <button id="submit" text="提交表单" marginTop="24"/>
        <text id="errorMsg" textColor="#F44336" textSize="12sp" visibility="gone"/>
    </vertical>
);

function validate(username, email, age) {
    let errors = [];
    
    if (username.length < 3 || username.length > 16) {
        errors.push("用户名需 3-16 位");
    }
    
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
        errors.push("邮箱格式不正确");
    }
    
    let ageNum = parseInt(age);
    if (isNaN(ageNum) || ageNum < 1 || ageNum > 150) {
        errors.push("年龄需在 1-150 之间");
    }
    
    return errors;
}

ui.submit.click(() => {
    let username = ui.username.getText();
    let email = ui.email.getText();
    let age = ui.age.getText();
    
    let errors = validate(username, email, age);
    
    if (errors.length > 0) {
        ui.errorMsg.setText(errors.join("\n"));
        ui.errorMsg.attr("visibility", "visible");
    } else {
        ui.errorMsg.attr("visibility", "gone");
        toast("表单验证通过");
    }
});

// 输入变化时实时清除错误提示
ui.username.on("change", () => ui.errorMsg.attr("visibility", "gone"));
ui.email.on("change", () => ui.errorMsg.attr("visibility", "gone"));
ui.age.on("change", () => ui.errorMsg.attr("visibility", "gone"));