更新记录

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 正方形简写,等价于同时设置 widthheight,默认 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: falseedgeSnap: 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 与颜色关键字(如 redblack),不支持 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 不会在首次触发后自动回收回调,可以持续点击。请不要把点击逻辑写在 showFloatingBalloptions 里,推荐始终使用本 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:点击回调不触发?

按以下顺序排查:

  1. 确认已通过 onFloatingBallClick(cb) 注册回调,回调在 showFloatingBall 前后注册均可;
  2. 确认自定义调试基座已重新制作——插件更新不会热更新;
  3. 若自定义了 touchSlop,取值过小会把点击误判为拖拽(此时不会触发点击回调);
  4. 按压超过 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 / FloatingBallShowResultsize 字段拆分为 width / heightFloatingBallPosition 移除多余的 size 字段;新增 FloatingBallPositionInfo

1.0.0

  • 首个版本:悬浮球显示 / 隐藏、拖拽、贴边吸附、点击与长按回调、数字与红点角标、图标与位置动态更新、悬浮窗权限封装

隐私、权限声明

1. 本插件需要申请的系统权限列表:

android.permission.SYSTEM_ALERT_WINDOW(悬浮窗权限,用于在其他应用上层显示悬浮球)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

本插件不采集任何数据,不涉及服务器地址

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。