欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android悬浮窗的实现步骤,

来源: 开发者 投稿于  被查看 3679 次 评论:54

Android悬浮窗的实现步骤,


目录
  • 1、初识WindowManager
  • 2、设置权限
  • 3、LayoutParam设置
  • 4、检测是否允许开启悬浮窗
  • 5、FloatingService服务
  • 6、启动FloatingService
  • 7、增加拖动功能

最近想做一个悬浮窗秒表的功能,所以看下悬浮窗具体的实现步骤

1、初识WindowManager

实现悬浮窗主要用到的是WindowManager

@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
	...
}

WindowManager是接口类,继承自接口ViewManager,可以通过获取WINDOW_SERVICE系统服务得到。而ViewManager接口有addView方法,我们就是通过这个方法将悬浮窗控件加入到屏幕中去。

2、设置权限

当API Level >= 23,显示悬浮窗功能,需要在清单文件AndroidManifest.xml中添加SYSTEM_ALERT_WINDOW权限,添加这个权限后才可以在其他应用上显示悬浮窗。

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

通过getSystemService方式获取WindowManager

val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager

3、LayoutParam设置

WindowManager的addView方法有两个参数,一个是需要加入的控件对象,另一个参数是WindowManager.LayoutParams对象。

// view – The view to be added to this window.
	// params – The LayoutParams to assign to view.
   public void addView(View view, ViewGroup.LayoutParams params);

其中LayoutParams的type变量,这个变量是用来指定窗口的类型。在设置这个变量时,需要对不同版本的Android系统进行适配。

        val layoutParams = WindowManager.LayoutParams()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE
        }

在Android 8.0之前,悬浮窗口设置可以为TYPE_PHONE,这种类型是用于提供用户交互操作的非应用窗口,现在这个类型已弃用了。
而Android 8.0对系统和API行为做了修改,包括使用SYSTEM_ALERT_WINDOW权限的应用无法再使用窗口类型来在其他应用和窗口上方显示提醒窗口:

  • TYPE_PHONE(已弃用)

  • TYPE_PRIORITY_PHONE

  • TYPE_SYSTEM_ALERT

  • TYPE_SYSTEM_OVERLAY

  • TYPE_SYSTEM_ERROR

如果需要实现在其他应用和窗口上方显示提醒窗口,那么必须该为TYPE_APPLICATION_OVERLAY的新类型。

4、检测是否允许开启悬浮窗

开启悬浮窗之前,还需要检测用户是否允许开启悬浮窗,通过系统提供的canDrawOverlays来检测

//检测是否允许开启悬浮窗
Settings.canDrawOverlays(context)

如果没有允许开启,需要跳转开启页面,让用户允许开启悬浮窗

startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION))

5、FloatingService服务

悬浮窗一直显示在其他应用上层,需要新建FloatingService服务类,用于处理悬浮窗相关逻辑。

class FloatingService : Service() {
    override fun onCreate() {
        super.onCreate()
    }
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        showFloatingWindow();
        return super.onStartCommand(intent, flags, startId)
    }
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
    /**
     * 显示悬浮窗
     */
    private fun showFloatingWindow() {
        // 获取WindowManager服务
        val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
        // 新建悬浮窗控件
        val button = Button(applicationContext)
        button.text = "Floating Window"
        button.setBackgroundColor(Color.BLUE)
        // 设置LayoutParam
        val layoutParams = WindowManager.LayoutParams()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE
        }
        layoutParams.format = PixelFormat.RGBA_8888
        layoutParams.flags =
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        layoutParams.width = ActionBar.LayoutParams.WRAP_CONTENT
        layoutParams.height = ActionBar.LayoutParams.WRAP_CONTENT
        layoutParams.x = 300
        layoutParams.y = 300
        // 将悬浮窗控件添加到WindowManager
        windowManager.addView(button, layoutParams);
    }
}

6、启动FloatingService

       viewBinding.btnFloating.setOnClickListener {
            if (Settings.canDrawOverlays(this)) {//检测是否具有悬浮窗权限
                startService(Intent(this,FloatingService::class.java))
            } else {
                startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
            }
        }

开启效果如下:

7、增加拖动功能

悬浮窗显示的位置可能会遮挡其他信息,这时就需要新增拖动功能,可以拖动到任何位置,实现的逻辑就是给布局View添加触摸事件,根据触摸和移动的位置来决定悬浮窗显示的位置。

        var x = 0
        var y = 0
        button.setOnTouchListener { view, event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    x = event.rawX.toInt()
                    y = event.rawY.toInt()
                }
                MotionEvent.ACTION_MOVE -> {
                    val nowX = event.rawX.toInt()
                    val nowY = event.rawY.toInt()
                    val movedX = nowX - x
                    val movedY = nowY - y
                    x = nowX
                    y = nowY
                    layoutParams.x = layoutParams.x + movedX
                    layoutParams.y = layoutParams.y + movedY
                    // 更新悬浮窗控件布局
                    windowManager.updateViewLayout(view, layoutParams)
                }
                else -> {}
            }
            false
        }

到此这篇关于Android悬浮窗的实现的文章就介绍到这了,更多相关Android悬浮窗内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

您可能感兴趣的文章:
  • Android 无障碍全局悬浮窗实现示例
  • Android应用内悬浮窗Activity的简单实现
  • Android超简单悬浮窗使用教程
  • Android实现悬浮窗的简单方法实例
  • Android仿IOS系统悬浮窗效果
  • Android创建悬浮窗的完整步骤
  • Android仿优酷视频的悬浮窗播放效果
  • Android仿微信视屏悬浮窗效果
  • Android悬浮窗按钮实现点击并显示/隐藏多功能列表

用户评论