让悬浮窗能够被拖动可以使用w.setAdjustEnabled(true);来实现。但是这样会给悬浮窗上面加三个大按钮,很不好看。有没有什么方法可以不使用这个w.setAdjustEnabled(true);来让悬浮窗可以被拖动?我看别人写的脚本可以不使用这个函数而且还能被拖动,而且可以按住窗体的任何位置来进行拖动,非常方便。
我查看了文档,events.observeTouch()这东西需要 root 权限,我没开启所i没法使用,因此我想不到可以实现此功能的方法了。

SilverFox0-6 · 7 小时前

回答

Hamibot AI
1
· 7 小时前

要实现不依赖 setAdjustEnabled(true) 且无需 Root 权限的任意位置拖动悬浮窗,可以通过为悬浮窗的根布局绑定原生触摸监听器 setOnTouchListener,记录按下时的屏幕坐标与窗口坐标,在移动时计算偏移量并调用 setPosition() 更新位置。

以下是完整可运行的示例代码(已适配 Rhino 1.7.15 引擎,未使用箭头函数与默认参数):

// 文档地址 https://docs.hamibot.com/
var w = floaty.window(
    <frame id="root" bg="#44ffcc00" w="200" h="100">
        <text text="按住任意位置拖动" gravity="center" textColor="#000000" />
    </frame>
);

var MotionEvent = android.view.MotionEvent;
var initialX = 0;
var initialY = 0;
var windowX = 0;
var windowY = 0;

w.root.setOnTouchListener(function(view, event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            initialX = event.getRawX();
            initialY = event.getRawY();
            windowX = w.getX();
            windowY = w.getY();
            return true;
        case MotionEvent.ACTION_MOVE:
            var newX = windowX + (event.getRawX() - initialX);
            var newY = windowY + (event.getRawY() - initialY);
            w.setPosition(newX, newY);
            return true;
        case MotionEvent.ACTION_UP:
            return true;
    }
    return false;
});

// 保持脚本运行,防止悬浮窗随脚本结束自动关闭
setInterval(function() {}, 1000);

核心原理说明

  1. 触摸事件拦截setOnTouchListener 直接绑定在根布局 root 上,拦截整个窗口的触摸事件,无需 Root 权限。
  2. 坐标计算
    • ACTION_DOWN 时记录手指的绝对屏幕坐标 getRawX()/getRawY() 和当前窗口左上角坐标 w.getX()/w.getY()
    • ACTION_MOVE 时计算手指移动的差值,叠加到初始窗口坐标上,通过 w.setPosition() 实时更新位置。
  3. 事件消费:返回 true 表示当前监听器已消费该触摸事件,悬浮窗会跟随手指移动,不会将事件传递给下层应用。

注意事项

  • 脚本保活:悬浮窗的生命周期与脚本绑定,必须使用 setIntervalevents.on("exit", ...) 等机制保持脚本运行,否则窗口会立即销毁。
  • 内部控件点击冲突:由于根布局消费了 ACTION_DOWN 事件,窗口内的按钮或文本默认无法触发点击。如果窗口内需要保留可点击控件,建议将拖动监听器绑定到指定的“拖动条”或“标题栏”布局上,而不是整个根布局。
  • 性能优化setPosition() 调用频率较高,Rhino 环境下表现稳定。若拖动时出现轻微卡顿,可限制刷新频率(例如记录上次更新时间,间隔 16ms 再调用 setPosition),但通常无需额外处理。
  • 兼容性:代码严格遵循 Rhino 1.7.15 语法规范,未使用 ES6 特性,可在 Hamibot 环境中直接运行。

你可以直接复制上述代码到 Hamibot 脚本编辑器中运行测试。如需调整窗口大小、背景透明度或添加内部交互控件,只需修改 XML 布局部分即可。

ℹ️ 内容由 AI 生成,可能不准确,请注意核实