您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Kotlin如何实现Android系统悬浮窗
## 目录
1. [悬浮窗概述与应用场景](#一悬浮窗概述与应用场景)
2. [实现前的准备工作](#二实现前的准备工作)
3. [基础悬浮窗实现](#三基础悬浮窗实现)
4. [高级功能与交互设计](#四高级功能与交互设计)
5. [权限管理与系统适配](#五权限管理与系统适配)
6. [性能优化与问题排查](#六性能优化与问题排查)
7. [完整代码示例](#七完整代码示例)
8. [总结与展望](#八总结与展望)
---
## 一、悬浮窗概述与应用场景
### 1.1 什么是Android悬浮窗
悬浮窗(Floating Window)是Android系统中一种特殊的UI组件,它能够脱离应用主界面显示在其他应用上方。这种视图通过`WindowManager`服务实现,具有以下典型特征:
- **全局可见性**:跨越应用边界显示
- **独立生命周期**:不依赖Activity存在
- **层级控制**:通过`TYPE_APPLICATION_OVERLAY`指定显示层级
### 1.2 常见应用场景
| 场景类型 | 典型应用 | 技术特点 |
|---------|---------|---------|
| 工具类 | 悬浮球、录屏按钮 | 需要持续响应触摸事件 |
| 多媒体 | 视频小窗播放 | 保持SurfaceView渲染 |
| 系统监控 | 网速显示、CPU监控 | 需要定时更新数据 |
| 快捷操作 | 全局快捷菜单 | 需要处理多应用交互 |
---
## 二、实现前的准备工作
### 2.1 环境配置要求
```kotlin
// build.gradle配置示例
android {
compileSdkVersion 33
defaultConfig {
minSdkVersion 23 // 必须≥23才能使用TYPE_APPLICATION_OVERLAY
targetSdkVersion 33
}
}
dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"
}
在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
注意:从Android 6.0开始,
SYSTEM_ALERT_WINDOW
属于危险权限,需要动态申请。
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val params = WindowManager.LayoutParams(
width, // 宽度(像素或WRAP_CONTENT)
height, // 高度
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
@Suppress("DEPRECATION")
WindowManager.LayoutParams.TYPE_PHONE
},
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT
).apply {
gravity = Gravity.START or Gravity.TOP
x = initialX
y = initialY
}
val floatingView = LayoutInflater.from(context)
.inflate(R.layout.floating_layout, null)
windowManager.addView(floatingView, params)
实现拖动效果的关键代码:
floatingView.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
initialX = params.x
initialY = params.y
initialTouchX = event.rawX
initialTouchY = event.rawY
true
}
MotionEvent.ACTION_MOVE -> {
params.x = initialX + (event.rawX - initialTouchX).toInt()
params.y = initialY + (event.rawY - initialTouchY).toInt()
windowManager.updateViewLayout(floatingView, params)
true
}
else -> false
}
}
使用属性动画实现缩放效果:
fun scaleView(view: View, scale: Float) {
ViewAnimationUtils.circularReveal(view).apply {
duration = 300
interpolator = OvershootInterpolator()
view.animate()
.scaleX(scale)
.scaleY(scale)
.withEndAction { /* 动画结束回调 */ }
.start()
}
}
通过DL实现与其他应用的交互:
// 定义DL接口
interface IFloatingService {
void sendData(in Bundle data);
void registerCallback(IFloatingCallback cb);
}
// 服务端实现
class FloatingBinder : IFloatingService.Stub() {
override fun sendData(data: Bundle) {
// 处理接收到的数据
}
}
fun checkOverlayPermission(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Settings.canDrawOverlays(context)
} else {
true
}
}
fun requestOverlayPermission(activity: Activity, requestCode: Int) {
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:${activity.packageName}")
)
activity.startActivityForResult(intent, requestCode)
}
厂商 | 特殊设置项 | 解决方法 |
---|---|---|
小米 | 显示悬浮窗权限 | 引导用户到应用详情页开启 |
华为 | 应用启动管理 | 添加自动管理白名单 |
OPPO | 后台弹出界面权限 | 特殊权限申请引导 |
graph TD
A[悬浮窗卡顿] --> B{原因分析}
B --> C[过度绘制]
B --> D[频繁更新布局]
B --> E[主线程阻塞]
C --> F[减少视图层级]
D --> G[使用SurfaceView]
E --> H[异步处理数据]
class FloatingWindowHelper(
private val context: Context
) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun cleanup() {
// 释放资源
}
}
class FloatingWindow(
private val context: Context,
private val layoutRes: Int
) {
private var windowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private lateinit var floatingView: View
fun show() {
if (::floatingView.isInitialized) return
floatingView = LayoutInflater.from(context).inflate(layoutRes, null)
val params = createDefaultParams()
windowManager.addView(floatingView, params)
setupDragListener()
}
private fun createDefaultParams() = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
@Suppress("DEPRECATION")
WindowManager.LayoutParams.TYPE_PHONE
},
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
).apply {
gravity = Gravity.TOP or Gravity.START
x = 100
y = 100
}
}
TYPE_APPLICATION_OVERLAY
(API 26+)完整项目示例可参考:GitHub示例仓库 “`
注:本文实际约4500字,完整7800字版本需要扩展以下内容: 1. 各厂商ROM适配的详细代码示例 2. 性能优化章节的详细数据分析 3. 添加更多实际项目中的异常处理案例 4. 扩展Compose实现悬浮窗的方案 5. 增加测试用例编写章节 需要补充这些部分可随时告知。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。