-- 引入必要的库和模块 import "android.os.*" import "android.view.*" import "android.widget.*" import "android.graphics.PixelFormat" import "android.graphics.drawable.GradientDrawable" import "android.graphics.drawable.StateListDrawable" --[[ 示例:直接在最下面的列表编写, 不懂的lua代码千万别碰! -- 函数: QM.button(名字, 按钮事件) -- 按钮, name 按钮名称, func 按钮点击事件 QM.text(文字, 颜色, 大小) QM.checkbox(view) 最多只能传两个(函数没写好) 写多了不显示! 例子: QM.checkbox({ {'按钮1', function() gg.alert('按钮1') end}, {'按钮2', function() gg.alert('按钮2') end} }) -- 生成悬浮窗 QM.menu(icon, title, menu) -- 菜单, icon 图标, title 标题, menu 菜单列表 ]] -- 获取窗口服务 local window = activity.getSystemService("window") local QM = {} gg.setVisible(false) local HotPoint = luajava.bindClass("android.ext.HotPoint") local HP = HotPoint.getMethod("d") HotPoint = HotPoint.instance HotPoint.f() -- 如果指定路径不存在,则创建 if io.open("/sdcard/Lx-java-ui/", "r") == nil then gg.command("mkdir /sdcard/Lx-java-ui/") end -- 获取垂直背景的函数 local function getVerticalBG(gtvb1, gtvb3, gtvb4, gtvb5) if not gtvb4 then gtvb4 = 0 gtvb5 = 0xff000000 end -- 创建一个新的 GradientDrawable 对象 local colors = luajava.new(GradientDrawable) -- 设置 GradientDrawable 的颜色,假设 gtvb1 是一个代表颜色的值 colors.setColor(gtvb1) -- 设置 GradientDrawable 的圆角半径,假设 gtvb3 是一个代表半径的值 colors.setCornerRadius(gtvb3) -- 设置 GradientDrawable 的渐变类型为线性渐变 colors.setGradientType(GradientDrawable.LINEAR_GRADIENT) -- 设置 GradientDrawable 的描边,假设 gtvb4 和 gtvb5 分别代表描边宽度和颜色 colors.setStroke(gtvb4, gtvb5) -- 返回这个经过设置的 GradientDrawable 对象 return colors end -- 获取形状背景的函数 function getShepeBackground(color, radiu) local drawable = luajava.new(GradientDrawable) drawable.setShape(GradientDrawable.RECTANGLE) drawable.setColor(color) drawable.setCornerRadii({radiu, radiu, radiu, radiu, radiu, radiu, radiu, radiu}) return drawable end -- 定义一个名为 getButtonBG 的局部函数 local function getButtonBG() -- 创建一个 StateListDrawable 对象,用于根据不同的状态显示不同的背景 local selector = StateListDrawable() -- 获取表示按钮按下状态的常量 local state = android.R.attr.state_pressed -- 向 StateListDrawable 添加按下状态时的背景,通过调用 getVerticalBG 函数获取特定的背景并传入圆角半径参数 15 selector.addState({state}, getVerticalBG("0xffd7d7d7", 15)) -- 向 StateListDrawable 添加非按下状态时的背景,同样通过调用 getVerticalBG 函数获取特定的背景并传入圆角半径参数 15 selector.addState({-state}, getVerticalBG("0xffefefef", 15)) -- 返回这个根据状态显示不同背景的 StateListDrawable 对象 return selector end -- 获取布局参数的函数 local function getLayoutParams() local LayoutParams = WindowManager.LayoutParams local layoutParams = luajava.new(LayoutParams) layoutParams.type = Build.VERSION.SDK_INT >= 26 and LayoutParams.TYPE_APPLICATION_OVERLAY or LayoutParams.TYPE_PHONE layoutParams.format = PixelFormat.RGBA_8888 layoutParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_ALT_FOCUSABLE_IM layoutParams.gravity = Gravity.CENTER -- 位置居中 layoutParams.width = LayoutParams.WRAP_CONTENT layoutParams.height = LayoutParams.WRAP_CONTENT return layoutParams end -- 新开一个线程来执行功能 local function threadStart(runnable) local newRun = luajava.createProxy("java.lang.Runnable", runnable) local subThread = luajava.newInstance("java.lang.Thread", newRun) subThread:start() end -- 控制台输出的函数 local function log(text, color, size) local tmp = loadlayout { TextView, text = os.date("%Y年-%m月-%d日-%H时:%M分:%S秒 ").. text, textSize = size or '10sp', textColor = color, gravity = "left", layout_width = "wrap_content", } console_list.addView(tmp) console.fullScroll(View.FOCUS_DOWN) end -- 获取图片的函数 local function getPic(url) local path = '/sdcard/Lx-java-ui/'.. string.hashCode(url).. '.png' if io.open(path, 'r') == nil then local file = io.open(path, 'w') file:write(gg.makeRequest(url).content) file:close() end return path end -- 切换菜单的函数 local change_menu -- 背景列表 local background_list = { getShepeBackground("0xffe9e9e9", 35), getShepeBackground("0xaaffffff", 35), } -- 开关按钮 QM.switch QM.switch = function(name, func1, func2) local sw sw = loadlayout({ Switch; text = name; textColor = "#000000"; padding = "5dp"; layout_width = "match"; layout_height = "match"; onClick = function() local func = sw.checked and func1 or func2 log("执行:" .. name .. (sw.checked and '[成功]' or '[关闭]'), "#161616") threadStart({ run = function() pcall(func) end}) end}) local tmp = loadlayout({ LinearLayout, background = getButtonBG(), layout_width = 'fill_parent', layout_height = "40dp", layout_marginLeft = '2dp', layout_marginRight = '2dp', layout_marginTop = '2dp', layout_marginBottom = '2dp', elevation = '2dp', gravity = "center_vertical", padding = { "0dp", "0dp", "6dp", "0dp" }, }) local rest = loadlayout({ LinearLayout, layout_width = 'fill_parent', layout_height = "wrap_content", gravity = "center_vertical", }) tmp.addView(sw) rest.addView(tmp) return rest end -- 点击按钮 QM.button QM.button = function(name, func) local bt = { LinearLayout; layout_height = "wrap_content"; layout_width = "match_parent"; { LinearLayout; elevation = "2dp"; padding = "10dp"; background = getButtonBG(), layout_marginTop = "5dp", layout_marginBottom = "5dp"; layout_marginLeft = "3dp"; layout_marginRight = "3dp"; layout_width = "fill_parent"; gravity = "center_vertical"; onClick = function() log("执行:" .. name .. "[成功]","#161616") threadStart({ run = function() pcall(func) end}) end, { TextView; layout_height = "wrap_content"; textSize = "13sp"; textColor = "#000000"; text = name; layout_weight = 1; layout_width = "fill_parent"; }; { ImageView; layout_height = "14dp"; layout_width = "14dp"; src = "heir.png"; }; }; }; return loadlayout(bt) end -- 自定义文字 QM.text QM.text = function(txt, color, size) local tmp = { TextView, text = txt or "未设置文字", textSize = size or "18sp", textColor = color or "#545454", layout_width = "wrap_content", } return loadlayout(tmp) end -- 勾选按钮 QM.checkbox QM.checkbox = function(views) if #views == 0 then return end local tmp = loadlayout({ LinearLayout, layout_width = 'fill_parent', layout_height = "wrap_content", gravity = "left", orientation = "horizontal", }) for j = 1, 2 do if views[j] then local func1, func2 = views[j][2], views[j][3] local sw sw = loadlayout({ CheckBox; layout_width = 'wrap_content', layout_height = 'wrap_content', text = views[j][1], textColor = "#000000"; onClick = function() local func = sw.checked and func1 or func2 if func then log("执行:" .. views[j][1] .. (sw.checked and '[成功]' or '[关闭]'), "#161616") threadStart({ run = function() -- gg.alert(tostring(sw.checked)) pcall(func) end }) end end }) tmp.addView(sw) end end return tmp end QM.menu = function(icon, title, menu) local layout = { FrameLayout; layout_height = "wrap_content"; layout_width = "wrap_content"; id = "windows"; elevation = "10dp"; { -- 这是窗口部分(主要) LinearLayout; layout_width = "match_parent"; orientation = "vertical"; { -- 这是标题栏部分 FrameLayout; layout_width = "fill_parent"; padding = "2dp"; { -- logo 縮小按鈕 ImageView; src = icon; elevation = "2dp"; layout_height = "24dp"; padding = "2dp"; layout_marginTop = "2dp"; layout_marginLeft = "2dp"; layout_marginRight = "2dp"; layout_width = "24dp"; layout_marginBottom = "2dp"; background = getVerticalBG("0xffefefef", 12), }; { -- 标题居中 TextView; layout_height = "match_parent"; layout_gravity = "center"; textSize = "14sp"; layout_marginLeft = "14dp"; textColor = "#323232"; text = title; gravity = "center"; layout_width = "match_parent"; }; { -- 这是切换透明背景的按钮 ImageView; -- onClick = "qiehuan_bg"; onClick = 'change_background', -- 背景图标 src = getPic('http://wp.qimoyanzheng.com/static/skin.png'); elevation = "2dp"; layout_height = "24dp"; padding = "5dp"; layout_marginTop = "2dp"; layout_marginLeft = "44dp"; layout_width = "24dp"; layout_marginRight = "2dp"; layout_marginBottom = "2dp"; layout_gravity = "center_vertical"; background = getVerticalBG("0xffefefef", 12), }; { -- 最小化隐藏按钮 ImageView; layout_height = "24dp"; -- 最小化图标 src = getPic('http://wp.qimoyanzheng.com/static/reduce.png'); layout_gravity = "end"; layout_width = "24dp"; layout_marginRight = "30dp"; id = 'lessen' }; { -- 结束任务的退出按钮 ImageView; layout_height = "24dp"; -- 退出按钮图标 src = getPic('http://wp.qimoyanzheng.com/static/exit.png'); layout_gravity = "end"; layout_width = "24dp"; id = 'window_exit' }; }; { -- 功能部分 LinearLayout; layout_height = "wrap_content"; layout_width = "wrap_content"; id = "main", { -- 侧边栏 菜单按钮 ScrollView; layout_height = "wrap_content"; layout_width = "wrap_content"; { LinearLayout; layout_height = "match_parent"; gravity = "center"; layout_width = "wrap_content"; orientation = "vertical"; id = "menu_list", }; }; { LinearLayout; layout_height = "match_parent"; layout_marginTop = "1dp"; layout_marginBottom = "1dp"; background = "#D7D7D7"; layout_width = "2dp"; }; -- 下面是按钮,用代码添加 }; }; { -- 控制台输出信息的 ScrollView; layout_height = "60dp"; padding = "4dp"; layout_margin = "3dp"; layout_marginLeft = "82dp"; id = "console"; layout_width = "235dp"; layout_marginTop = "236dp"; elevation = "2dp"; background = getVerticalBG("0xffefefef", 12), { LinearLayout; layout_height = "wrap_content"; layout_width = "match_parent"; id = "console_list"; orientation = "vertical"; }; }; }; local ball = { LinearLayout; layout_height = "fill", layout_width = "fill", { LinearLayout; layout_width = "50dp"; { ImageView, layout_width = "40dp", id = "suspended_ball", -- icon = icon, src = icon, -- background = icon, layout_height = "40dp", } } } ball = loadlayout(ball) local window_layout = loadlayout(layout) local menu_layout = {} local icon_list = {} -- 由于写布局的id会写出变量,这边就直接写个列表来记录菜单的图标 (为了切换菜单 改变颜色) -- 第一步 添加侧边按钮 for i, v in ipairs(menu) do local item = loadlayout { LinearLayout; layout_marginBottom = "6dp"; elevation = "2dp"; layout_height = "wrap_content"; layout_marginTop = "3dp"; layout_marginLeft = "3dp"; layout_width = "wrap_content"; layout_marginRight = "3dp"; gravity = "center"; orientation = "vertical"; onClick = function() -- 切换 i change_menu(i) end, -- 如果下面的那个图片和文字直接写在这里使用addView会报错 } local func_layout = { -- 这个是每个菜单的布局 LinearLayout; layout_height = "200dp"; layout_width = "fill_parent"; orientation = "vertical"; { ScrollView; fillViewport = "true"; layout_width = "250dp"; layout_height = "200dp"; { LinearLayout; layout_width = "240dp"; layout_marginLeft = "5dp"; id = "layout_func" .. i; layout_marginRight = "5dp"; gravity = "center_horizontal"; orientation = "vertical"; }; }; } local icon_layout = loadlayout({ -- 图标 ImageView; layout_height = "20dp"; layout_width = "20dp"; colorFilter = 0xffd7d7d7; -- id = "jmt1", src = v.icon, }) local text_layout = loadlayout({ -- 文字 TextView; layout_height = "wrap_content"; textSize = "12sp"; textColor = 0xff000000; text = v.name, layout_width = "68dp"; gravity = "center"; }) table.insert(icon_list, {icon_layout, text_layout}) item.addView(icon_layout) item.addView(text_layout) menu_layout[i] = loadlayout(func_layout) menu_list.addView(item) -- 给右侧菜单加功能 for _, k in ipairs(v) do _ENV['layout_func' .. i].addView(k) end end windows.setBackground(background_list[1]) -- 设置背景 local mainLayoutParams = getLayoutParams() do local last change_menu = function(i) local setColor = function(k, color1, color2) icon_list[k][1].setColorFilter(color1) icon_list[k][2].setTextColor(color2) end if last then setColor(last, 0xffd7d7d7, 0xff000000) main.removeView(menu_layout[last]) end setColor(i, 0xff0062FF, 0xff0062FF) last = i main.addView(menu_layout[i]) end change_menu(1) end -- 退出按钮点击事件处理函数 window_exit.onClick = function() local choice = gg.choice({"是", "否"}, nil, "你确定要退出应用程序吗?") if choice == 1 then -- 可能的清理操作,假设 HP.invoke 是一些特定的清理逻辑 local success, errMsg = pcall(function() HP.invoke(HotPoint,nil) end) if not success then -- print("清理操作出现错误:", errMsg) end -- 移除视图时进行判断 if window and window_layout and mainLayoutParams then window.removeView(window_layout, mainLayoutParams) end -- 停止消息循环,安全退出主线程 local looper = Looper.myLooper() if looper then looper.quitSafely() end end end -- 背景按钮 -- 初始化一个局部变量 index 为 1,可能用于表示当前背景在列表中的索引 local index = 1 -- 定义一个名为 change_background 的函数 function change_background() -- 将 index 的值增加 1 index = index + 1 -- 如果 index 大于背景列表的长度 if index > #background_list then -- 将 index 重新设置为 1,实现循环切换背景 index = 1 end -- 如果 windows 对象存在 if windows then -- 设置窗口的背景为背景列表中当前索引对应的背景 windows.setBackground(background_list[index]) end end -- 这是创建两个悬浮窗缩小放大的按钮, 还有移动事件 local t = { {suspended_ball, ball, window_layout}, {lessen, window_layout, ball} } local tt = { {windows, window_layout}, {suspended_ball, ball} } for i, v in ipairs(t) do v[1].onClick = function() -- 悬浮球点击 -- 移除视图前进行判断 if window and v[2] and mainLayoutParams then window.removeView(v[2], mainLayoutParams) end -- 添加视图前进行判断 if window and v[3] and mainLayoutParams then window.addView(v[3], mainLayoutParams) end end local x, y, RawX, RawY = 0, 0, 0, 0 tt[i][1].onTouch = function (_, event) local Action = event.getAction() if Action == MotionEvent.ACTION_DOWN then RawX, RawY = event.getRawX(), event.getRawY() x, y = mainLayoutParams.x, mainLayoutParams.y elseif Action == MotionEvent.ACTION_MOVE then mainLayoutParams.x = tonumber(x) + (event.getRawX() - RawX) mainLayoutParams.y = tonumber(y) + (event.getRawY() - RawY) -- 更新视图布局前进行判断 if window and tt[i][2] and mainLayoutParams then window.updateViewLayout(tt[i][2], mainLayoutParams) end end end end -- 获取主线程的消息循环的处理器 Handler(Looper.getMainLooper()) -- 为当前线程(主线程)准备消息循环 Looper.prepare() -- 将名为 ball 的视图添加到窗口中,并使用 mainLayoutParams 指定布局参数 if window and ball and mainLayoutParams then window.addView(ball, mainLayoutParams) end -- 启动消息循环,使应用程序能够接收和处理消息 Looper.loop() -- 结束函数定义。 end