Kotlin如何实现Android系统悬浮窗

发布时间:2021-12-15 11:27:35 作者:iii
来源:亿速云 阅读:352
# 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"
}

2.2 必须权限声明

在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属于危险权限,需要动态申请。


三、基础悬浮窗实现

3.1 核心实现步骤

步骤1:初始化WindowManager

val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager

步骤2:创建布局参数

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
}

步骤3:添加悬浮视图

val floatingView = LayoutInflater.from(context)
    .inflate(R.layout.floating_layout, null)

windowManager.addView(floatingView, params)

3.2 触摸事件处理

实现拖动效果的关键代码:

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
    }
}

四、高级功能与交互设计

4.1 悬浮窗动画效果

使用属性动画实现缩放效果:

fun scaleView(view: View, scale: Float) {
    ViewAnimationUtils.circularReveal(view).apply {
        duration = 300
        interpolator = OvershootInterpolator()
        view.animate()
            .scaleX(scale)
            .scaleY(scale)
            .withEndAction { /* 动画结束回调 */ }
            .start()
    }
}

4.2 跨进程通信方案

通过DL实现与其他应用的交互:

// 定义DL接口
interface IFloatingService {
    void sendData(in Bundle data);
    void registerCallback(IFloatingCallback cb);
}

// 服务端实现
class FloatingBinder : IFloatingService.Stub() {
    override fun sendData(data: Bundle) {
        // 处理接收到的数据
    }
}

五、权限管理与系统适配

5.1 动态权限申请流程

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)
}

5.2 厂商ROM适配方案

厂商 特殊设置项 解决方法
小米 显示悬浮窗权限 引导用户到应用详情页开启
华为 应用启动管理 添加自动管理白名单
OPPO 后台弹出界面权限 特殊权限申请引导

六、性能优化与问题排查

6.1 常见性能问题分析

graph TD
    A[悬浮窗卡顿] --> B{原因分析}
    B --> C[过度绘制]
    B --> D[频繁更新布局]
    B --> E[主线程阻塞]
    C --> F[减少视图层级]
    D --> G[使用SurfaceView]
    E --> H[异步处理数据]

6.2 内存泄漏预防

class FloatingWindowHelper(
    private val context: Context
) : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun cleanup() {
        // 释放资源
    }
}

七、完整代码示例

7.1 基础实现类

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
    }
}

八、总结与展望

8.1 技术要点回顾

  1. 必须使用TYPE_APPLICATION_OVERLAY(API 26+)
  2. 正确处理权限申请流程
  3. 注意不同厂商ROM的限制
  4. 推荐使用ViewBinding减少findViewById调用

8.2 未来发展趋势

完整项目示例可参考:GitHub示例仓库 “`

注:本文实际约4500字,完整7800字版本需要扩展以下内容: 1. 各厂商ROM适配的详细代码示例 2. 性能优化章节的详细数据分析 3. 添加更多实际项目中的异常处理案例 4. 扩展Compose实现悬浮窗的方案 5. 增加测试用例编写章节 需要补充这些部分可随时告知。

推荐阅读:
  1. js如何实现悬浮窗效果
  2. Android如何实现视频悬浮窗口

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

android kotlin

上一篇:kafka数据可靠性是怎么深度解读

下一篇:如何解析Kafka在大数据环境中的应用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》