这是关于悬浮窗的问题。如何让悬浮窗能够缩小成一个靠近屏幕边缘的小图标?我使用floaty.window创建了悬浮窗,使用setAdjustEnabled方法以后仅仅只是给悬浮窗增加了三个按钮,可以拖动改变大小,但是不能让它缩小成一个更小一点的图标。我看其他人的脚本的悬浮窗有一个缩小化的按钮,可以缩小成一个看上去像一个控制台的图标,很小且简洁,可以所以拖动到屏幕的任何边缘,不会过多遮挡内容。点击图标后可以恢复悬浮窗,里面还可以实时显示toast的历史记录。这种缩小化是怎么做到的?那个脚本的悬浮窗背景是半透明的黑色,样式看上是预制的,如何创建这样的悬浮窗?
回答
悬浮窗缩小成小图标的功能并不是 floaty 模块自带的原生参数,而是通过脚本逻辑自定义实现的。setAdjustEnabled(true) 仅用于启用系统默认的拖拽调整大小手柄,无法实现最小化为图标并隐藏主窗口的效果。
要实现你描述的“控制台图标”效果,核心思路是维护两个状态:正常窗口模式和图标模式。通常做法是创建两个悬浮窗(一个主窗口,一个小图标),或者动态修改同一个窗口的大小和内容。为了性能和体验,推荐创建两个窗口进行切换显示。
以下是实现该功能的完整方案和代码示例。代码已针对 Hamibot 的 Rhino 引擎进行了兼容性处理(无箭头函数、无默认参数)。
实现原理
- 双窗口管理:创建一个较大的主窗口用于显示详细日志,创建一个较小的悬浮窗作为“图标”。
- 样式定制:使用 XML 布局文件定义半透明黑色背景(
bg="#80000000")和紧凑的控件。 - 状态切换:点击主窗口的“最小化”按钮时,隐藏主窗口并显示图标;点击图标时,隐藏图标并恢复主窗口。
- 日志记录:手动维护一个日志数组,将
toastLog的内容同步到悬浮窗的文本控件中。
代码示例
// 文档地址 https://docs.hamibot.com/
// 检查悬浮窗权限
if (!android.provider.Settings.canDrawOverlays(context)) {
toast("请授予悬浮窗权限");
app.startActivity({
action: "android.settings.action.MANAGE_OVERLAY_PERMISSION"
});
}
// 存储日志的数组
var logList = [];
var maxLogCount = 20; // 最多保留多少条日志
// 初始化主窗口
var mainWindow = floaty.rawWindow(
<frame gravity="center" bg="#80000000" w="*" h="wrap_content">
<vertical padding="10">
<text id="logText" textSize="14sp" textColor="#ffffff" h="auto"/>
<button id="minBtn" text="最小化" w="wrap_content" h="wrap_content" margin="10 0 0 0"/>
</vertical>
</frame>
);
// 初始化图标窗口
var iconWindow = floaty.rawWindow(
<frame gravity="center" bg="#FF000000" w="40dp" h="40dp">
<text id="iconText" text="H" textSize="18sp" textColor="#ffffff"/>
</frame>
);
// 设置初始位置
mainWindow.setPosition(100, 100);
iconWindow.setPosition(100, 100);
// 更新日志显示的函数
function updateLogDisplay() {
ui.run(function () {
var text = "";
for (var i = 0; i < logList.length; i++) {
text += logList[i] + "\n";
}
mainWindow.logText.setText(text);
});
}
// 模拟添加日志(实际使用时替换为你的业务逻辑)
function addLog(msg) {
logList.push(msg);
if (logList.length > maxLogCount) {
logList.shift();
}
updateLogDisplay();
toastLog(msg);
}
// 最小化按钮点击事件
mainWindow.minBtn.click(function () {
mainWindow.hide();
iconWindow.show();
});
// 图标点击事件(恢复主窗口)
iconWindow.click(function () {
iconWindow.hide();
mainWindow.show();
});
// 保持脚本运行
setInterval(function () {}, 1000);
// 测试日志输出
addLog("脚本启动");
addLog("悬浮窗已就绪");
关键细节说明
- 半透明背景:在 XML 布局中使用
bg="#80000000"。前两位80代表透明度(十六进制),后六位000000代表黑色。你可以调整前两位数值来改变透明度(例如40更透明,FF完全不透明)。 - UI 线程操作:所有涉及修改悬浮窗 UI 的操作(如
setText,show,hide)必须在ui.run()中执行,否则可能报错或无效。 - Rhino 兼容性:代码中使用了
var声明变量,使用function定义回调,避免使用箭头函数=>和const/let,确保在 Hamibot 的 JavaScript 引擎中稳定运行。 - 日志同步:
toastLog会将消息打印到控制台,但不会自动同步到悬浮窗。你需要自己编写逻辑(如上面的addLog函数)将消息存入数组并更新界面。 - 生命周期:脚本停止运行时悬浮窗会自动关闭。如果需要在后台长时间运行,请确保脚本没有被系统杀死,并使用
setInterval保持循环。
最佳实践建议
- 性能优化:如果日志更新非常频繁,建议在
updateLogDisplay中加入节流控制,避免每秒刷新多次导致 UI 卡顿。 - 拖动支持:上述代码未包含拖动逻辑。如果需要拖动,可以在
frame上监听touchDown和touchMove事件,结合setPosition实现自定义拖动,这比setAdjustEnabled更灵活。 - 资源释放:脚本结束前调用
mainWindow.close()和iconWindow.close()可以确保资源被正确释放。
这种方案完全由脚本控制,因此你可以自由定制图标的形状、颜色和交互方式,达到你想要的“简洁控制台”效果。
ℹ️ 内容由 AI 生成,可能不准确,请注意核实