更新记录
1.2.1(2026-09-16)
修复bug若干
1.2.0(2026-09-16)
- 新增满屏尺寸:
width/height传负数(推荐-1)时自动取屏幕尺寸,无需调用方自行换算 dp - 新增点击拉回前台:
bringToFrontOnClick: true时,点击悬浮球会把本应用切回前台(复用已有任务栈,不重建页面) - 优化:宽高解析统一走
resolveBallWidth/resolveBallHeight,屏幕尺寸刷新时机前置,修复满屏尺寸取不到屏幕宽度的问题 - 优化:窗口已显示时重复调用
showFloatingBall会先刷新屏幕尺寸,横竖屏切换后满屏尺寸能正确跟随 - 优化:
offFloatingBallClick注销时输出回调数量日志,便于排查回调丢失问题
平台兼容性
uni-app(3.8.4)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | √ | √ | √ | × | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(3.8.4)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | × | × | × | × |
lj-floatingball 桌面悬浮球
Android 平台的应用桌面悬浮球(UTS 插件)。悬浮球覆盖在桌面和其他 App 之上,支持自由拖拽、松手贴边吸附、点击 / 长按事件回传、数字角标与红点角标,并支持自定义形状(圆形 / 圆角矩形 / 长方形 / 胶囊)、背景色、图标与文字内容。
当前仅支持 Android 端。iOS 端为占位空实现,调用会走
fail回调并返回9010001。
授权与分发
本插件为插件市场付费加密插件,仅提供普通授权版,不提供源码授权版。
- 插件由 DCloud 插件市场加密后分发,交付内容为加密代码,不可查看、不可修改、不可单独导出;
- 授权绑定购买时使用的 AppID 与包名,更换其中任意一个都需要重新购买;
- 只支持从插件根目录导入,不支持导入插件内部文件:
// 正确
import { showFloatingBall } from '@/uni_modules/lj-floatingball'
// 错误
import { showFloatingBall } from '@/uni_modules/lj-floatingball/index.uts'
- 支持试用。试用版本可用于制作自定义调试基座验证功能,但不能用于正式发布。
打包方式限制
加密插件只支持云端传统打包,不支持离线打包,也不支持「安心打包」。
- 制作自定义调试基座请走云端打包流程;
- 若勾选「安心打包」或使用离线打包,会因为加密文件无法在本地解密而打包失败。
传统 uni-app 项目中,加密 UTS 插件仅可用于 App 端。本插件本身也只在 Android App 端提供实现,因此不受该限制影响。
目录结构
uni_modules/lj-floatingball
├── package.json
├── readme.md
├── changelog.md
└── utssdk
├── interface.uts 对外类型与 API 声明
├── unierror.uts 错误码与错误信息
├── app-android
│ ├── index.uts Android 实现
│ ├── AndroidManifest.xml SYSTEM_ALERT_WINDOW 权限
│ └── config.json minSdkVersion
└── app-ios
└── index.uts iOS 占位实现
接入准备
1. 权限
插件已在 utssdk/app-android/AndroidManifest.xml 中声明 android.permission.SYSTEM_ALERT_WINDOW。
如需在云打包时稳定生效,建议同时在项目根目录 manifest.json 的 App 权限配置中声明该权限。SYSTEM_ALERT_WINDOW 属于特殊权限,无法通过 uni.requestPermissions 弹窗申请,必须跳转系统设置页由用户手动开启,插件已封装好跳转逻辑。
2. 自定义基座
插件包含 AndroidManifest.xml、原生资源等原生层配置,必须制作自定义调试基座后才能真机运行,标准基座无法加载。
插件升级到新版本后,也需要重新制作自定义基座才能生效。
快速上手
import {
showFloatingBall,
hideFloatingBall,
updateFloatingBallBadge,
updateFloatingBallText,
onFloatingBallClick,
onFloatingBallLongPress,
FloatingBallOptions,
FloatingBallClickEvent
} from '@/uni_modules/lj-floatingball'
onFloatingBallClick((event: FloatingBallClickEvent) => {
console.log('悬浮球被点击', event.x, event.y, event.width, event.height)
})
onFloatingBallLongPress((event: FloatingBallClickEvent) => {
updateFloatingBallBadge(0)
})
const options = {
width: 120,
height: 56,
radius: 28,
backgroundColor: '#007AFF',
text: '客服',
badge: 3,
edgeSnap: true
} as FloatingBallOptions
showFloatingBall(options)
注意:
options必须使用as FloatingBallOptions断言,否则会被推断为UTSJSONObject,字段读取可能不符合预期。
形状与尺寸
形状由 width / height(决定长宽)+ radius(决定圆角) 两个维度组合而成。
| 参数 | 类型 | 单位 | 说明 |
|---|---|---|---|
width |
number |
dp | 球宽,优先级高于 size。传负数(推荐 -1)表示与屏幕等宽 |
height |
number |
dp | 球高,优先级高于 size |
size |
number |
dp | 正方形简写,等价于同时设置 width 与 height,默认 56 |
radius |
number |
dp | 圆角半径。不传 = 圆形;0 = 直角;> 0 = 对应半径的圆角 |
常见的四种形态:
// 1. 圆形(默认)
showFloatingBall({ size: 56 } as FloatingBallOptions)
// 2. 正方形 + 圆角
showFloatingBall({ size: 56, radius: 16 } as FloatingBallOptions)
// 3. 长方形(直角)
showFloatingBall({ width: 120, height: 56, radius: 0 } as FloatingBallOptions)
// 4. 胶囊形(圆角取高度的一半)
showFloatingBall({ width: 120, height: 56, radius: 28 } as FloatingBallOptions)
// 5. 满屏宽(width 传 -1,注意同时关掉拖拽与贴边)
showFloatingBall({
width: -1,
height: 56,
radius: 0,
margin: 0,
draggable: false,
edgeSnap: false
} as FloatingBallOptions)
尺寸优先级:width / height > size > 默认值 56。
满屏尺寸:width 传负数(推荐 -1)时,宽度自动取屏幕宽度,无需自己算 dp。此时水平方向不可拖拽、贴边吸附失效,建议同时传 draggable: false 与 edgeSnap: false;由于球宽等于屏宽,radius 不传会变成椭圆,满屏条请显式传 radius: 0 或具体圆角值。height 传负数同理(等于屏幕高度),但会占满整屏、拦截大量触摸,慎用。
内容构成
悬浮球由四部分叠加而成,可任意组合:
| 部分 | 来源 | 说明 |
|---|---|---|
| 背景 | backgroundColor / borderColor / borderWidth / radius |
形状与底色 |
| 图标 | icon |
球内图标,不传则不显示任何图片(显示纯色球) |
| 文字 | text / textColor / textSize |
居中显示的文字,可省略 |
| 角标 | badge / badgeDot 等 |
右上角数字或红点,可省略 |
图标与文字可以同时存在(两者都是居中的,实际使用时建议二选一)。
// 纯色球 + 文字
showFloatingBall({
width: 96,
height: 96,
radius: 48,
backgroundColor: '#007AFF',
text: '客服',
textColor: '#FFFFFF',
textSize: 18
} as FloatingBallOptions)
// 图片球 + 角标
showFloatingBall({
size: 56,
icon: '/static/ball.png',
badge: 5
} as FloatingBallOptions)
参数说明
showFloatingBall(options)
显示悬浮球。已显示时重复调用会更新配置:图标、文字、角标、位置即时生效;宽高、圆角、背景色、边框的变化会自动应用。
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
width |
number |
- | 球宽,单位 dp,优先级高于 size |
height |
number |
- | 球高,单位 dp,优先级高于 size |
size |
number |
56 |
正方形尺寸,单位 dp |
radius |
number |
-1(圆形) |
圆角半径,单位 dp |
icon |
string |
空(纯色球) | 球内图标。支持代码包路径(如 /static/ball.png)、沙盒绝对路径、file:// 协议路径、android_asset 路径。不支持网络图片,网络图请先用 uni.downloadFile 下载成本地文件再传入 |
text |
string |
空 | 球内文字,为空时不显示文字 |
textColor |
string |
#FFFFFF |
文字颜色 |
textSize |
number |
20 |
文字大小,单位 dp |
x |
number |
屏幕右侧 | 初始横坐标,单位 dp,相对屏幕左上角 |
y |
number |
屏高 62% | 初始纵坐标,单位 dp |
margin |
number |
8 |
贴边吸附时距屏幕边缘的距离,单位 dp |
draggable |
boolean |
true |
是否允许拖拽 |
edgeSnap |
boolean |
true |
松手后是否吸附到左右边缘 |
touchSlop |
number |
6 |
判定为拖拽的滑动阈值,单位 dp |
backgroundColor |
string |
#FFFFFF |
球背景色。支持 #RRGGBB、#AARRGGBB 与颜色关键字(如 red、black),不支持 rgb() / rgba() 写法 |
borderColor |
string |
#E8E8E8 |
球边框颜色,格式同上 |
borderWidth |
number |
0 |
球边框宽度,单位 dp,0 表示无边框 |
shadow |
boolean |
true |
是否显示投影 |
badge |
number |
0 |
角标数字,0 表示不显示 |
badgeDot |
boolean |
false |
是否只显示小红点 |
badgeColor |
string |
#FF3B30 |
角标背景色 |
badgeTextColor |
string |
#FFFFFF |
角标文字颜色 |
badgeTextSize |
number |
10 |
角标文字大小,单位 sp |
badgeMax |
number |
99 |
角标上限,超过显示为 99+ |
haptic |
boolean |
true |
点击时是否触发轻微震动反馈 |
longPress |
boolean |
注册长按回调时为 true |
是否启用长按事件 |
longPressDelay |
number |
500 |
长按判定时长,单位毫秒 |
autoRequestPermission |
boolean |
true |
无悬浮窗权限时是否自动跳转系统设置页 |
bringToFrontOnClick |
boolean |
false |
点击悬浮球时是否把本应用切回前台(仅 Android) |
success |
(res: FloatingBallShowResult) => void |
- | 成功回调,返回 errMsg / x / y / width / height |
fail |
(res: FloatingBallFail) => void |
- | 失败回调 |
complete |
(res: any) => void |
- | 完成回调 |
API
hideFloatingBall()
隐藏悬浮球。已注册的点击 / 长按回调会保留,下次 showFloatingBall 依然有效。
updateFloatingBallBadge(count)
设置数字角标。count <= 0 隐藏角标,超过 badgeMax 显示 99+。调用后自动切换到数字模式。
showFloatingBallBadgeDot(show)
切换红点角标。true 显示纯红点(无数字),false 隐藏。
updateFloatingBallIcon(icon)
运行时替换球内图标,参数规则同 options.icon。
- 传空字符串会清空图标,显示纯色球;
- 传入的路径无法解码时会保留当前图标(不会把球清空)。
该 API 只在悬浮球已显示时生效。
updateFloatingBallText(text)
运行时替换球内文字。传空字符串则隐藏文字。
该 API 只在悬浮球已显示时生效。
setFloatingBallPosition(position)
设置悬浮球位置。position 为 { x: number, y: number },单位 dp,越界会自动收敛到屏幕内。
getFloatingBallPosition()
返回 { x, y, width, height }(单位 dp)。
isFloatingBallShowing()
返回悬浮球当前是否显示。
isFloatingBallPermissionGranted()
返回是否已获得悬浮窗权限。
requestFloatingBallPermission()
已授权返回 true;未授权则跳转系统悬浮窗权限设置页并返回 false。建议在页面 onShow 中再次调用 isFloatingBallPermissionGranted() 确认用户是否授权成功。
onFloatingBallClick(callback) / offFloatingBallClick()
注册 / 注销点击回调。回调参数为 { x, y, width, height }(单位 dp,球的当前位置与尺寸)。
该 API 以
on开头且只有一个回调参数,UTS 不会在首次触发后自动回收回调,可以持续点击。请不要把点击逻辑写在showFloatingBall的options里,推荐始终使用本 API 注册。
点击拉回前台
传 bringToFrontOnClick: true 后,点击悬浮球会把本应用切回前台:
showFloatingBall({
width: 200,
height: 50,
radius: 48,
text: '客服',
bringToFrontOnClick: true
} as FloatingBallOptions)
行为说明:
- 应用在后台时,点击后切回前台并停留在用户离开时的页面,不会跳回首页
- 应用已在前台时无副作用,不闪烁、不跳转
- 点击回调中的逻辑不会被切前台打断
- Android 10 及以上同样可用
- 只有「点击」会触发,拖拽和长按都不会
- 仅 Android 生效,iOS 无对应能力
onFloatingBallLongPress(callback) / offFloatingBallLongPress()
注册 / 注销长按回调,参数同点击回调。注册后会自动启用长按判定。
动态更新方式
| 想改什么 | 用哪个 API |
|---|---|
| 图标 | updateFloatingBallIcon(path) 或 showFloatingBall({ icon }) |
| 文字 | updateFloatingBallText(text) 或 showFloatingBall({ text }) |
| 角标 | updateFloatingBallBadge(n) / showFloatingBallBadgeDot(bool) |
| 位置 | setFloatingBallPosition({ x, y }) 或 showFloatingBall({ x, y }) |
| 宽高 / 圆角 / 背景色 / 边框 | showFloatingBall({ ... }) |
宽高、圆角、背景色、边框的变化需要重新调用 showFloatingBall() 应用,不需要手动 hideFloatingBall(),并且会保持当前位置,不会跳回默认位置。
建议始终传入完整配置对象,避免未传的字段被重置成默认值:
const ballConfig = {
width: 120,
height: 56,
radius: 28,
backgroundColor: '#007AFF',
text: '客服',
badge: 3,
badgeColor: '#FF3B30',
edgeSnap: true,
draggable: true
} as FloatingBallOptions
showFloatingBall(ballConfig) // 首次创建
showFloatingBall({ ...ballConfig, width: 160 } as FloatingBallOptions) // 只改宽度
返回码
| errCode | 说明 |
|---|---|
9010001 |
当前平台不支持(iOS 或非 App 平台) |
9010002 |
未获得悬浮窗权限 |
9010003 |
悬浮球未显示 |
9010004 |
参数错误或上下文获取失败 |
常见问题
Q:为什么设置 backgroundColor 没效果?
如果同时传入了不透明的图标,背景色会被图标完全盖住。想要纯色球就不要传 icon;想要「彩色底 + 图标」,图标需要是带透明通道的 PNG。
Q:为什么角标看不见 / 被挡住?
请先确认已重新制作自定义调试基座——插件更新后基座必须重建,否则可能加载到旧版本。若重建后仍然异常,请联系插件作者。
Q:点击回调不触发?
按以下顺序排查:
- 确认已通过
onFloatingBallClick(cb)注册回调,回调在showFloatingBall前后注册均可; - 确认自定义调试基座已重新制作——插件更新不会热更新;
- 若自定义了
touchSlop,取值过小会把点击误判为拖拽(此时不会触发点击回调); - 按压超过
longPressDelay(默认 500ms)会触发长按回调而非点击回调。
Q:颜色字符串怎么写?
只支持 #RRGGBB、#AARRGGBB 以及颜色关键字(如 red)。写成 rgba(0,0,0,0.5) 会导致运行时报错,请改用 #80000000 这种 8 位十六进制写法。
Q:能用网络图片作为图标吗?
不能直接使用。请先用 uni.downloadFile 下载到本地,再把本地路径传给 icon。
Q:能渲染 HTML 或 uni-app 组件吗?
不能。悬浮球是系统级原生窗口,内容只能由原生 View 组成(图片、文字、形状、角标)。要做复杂 UI 请改用页面内的 movable-view 方案。
Q:应用被从最近任务划掉后悬浮球消失了?
这是 Android 的正常行为,进程被回收后悬浮球会一起消失。若需要更强的后台存活能力,需要额外接入前台服务。
最低版本要求
- HBuilderX 4.25 及以上
- Android 5.0(API 21)及以上;Android 6.0(API 23)及以上需要用户手动授予「显示在其他应用上层」权限
- 仅支持云端传统打包,不支持离线打包与「安心打包」
变更记录
1.2.0
- 新增满屏尺寸:
width/height传负数(推荐-1)时自动取屏幕尺寸,无需自行换算 dp - 新增点击拉回前台:
bringToFrontOnClick: true时,点击悬浮球会把本应用切回前台,并停留在用户离开时的页面 - 修复:满屏尺寸在横竖屏切换后未正确跟随
1.1.0
- 新增形状控制:
width/height支持长方形,radius支持圆角(圆形 / 圆角矩形 / 直角矩形 / 胶囊) - 新增文字内容:
text/textColor/textSize可在球上显示文字,新增updateFloatingBallText()动态更新 - 新增自动应用:
width/height/radius/backgroundColor变化时自动应用新配置,并保持当前位置 - 调整:
icon为空时不再加载 App 图标,改为显示纯色球;图标路径解码失败时保留原图标而非清空 - 调整:颜色只支持十六进制写法与颜色关键字,不再支持
rgb()/rgba() - 修复:角标显示异常;触摸监听偶发失效
- 类型清理:
FloatingBallClickEvent/FloatingBallShowResult的size字段拆分为width/height;FloatingBallPosition移除多余的size字段;新增FloatingBallPositionInfo
1.0.0
- 首个版本:悬浮球显示 / 隐藏、拖拽、贴边吸附、点击与长按回调、数字与红点角标、图标与位置动态更新、悬浮窗权限封装

收藏人数:
购买普通授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 2
赞赏 0
下载 12607838
赞赏 1949
赞赏
京公网安备:11010802035340号