背景
最近开发有个需求是在应用内展示悬浮窗,动态展示上传进度,当时就想到使用悬浮窗权限去addView,但由于体验问题,同时IOS那边是可以直接添加在window上,且不需要任何权限,因此这个方案被砍掉;
参考了各自开源库,都没发现直接能用的,就看了下实现原理,自己来写个。
思路
由于不能直接添加到主window上,因此只能在每个activity中进行添加,通过监听activity的生命周期,对悬浮窗进行动态显示隐藏。
1.activity生命周期
通过注册application的registerActivityLifecycleCallbacks方法进行监听
application.registerActivityLifecycleCallbacks(callback)
2.悬浮窗
由于多个页面共享同一个悬浮窗,因此悬浮窗需要是一个单例。
FloatWindow.getInstance().show(this)
FloatWindow.getInstance().hide()
3.添加到activity
经过查阅资料,发现WindowManager.LayoutParams的type类型分为系统、应用、子窗口,只有当类型为系统时(默认为系统),是需要申请悬浮窗权限的,其他是不用申请权限,但是只能展示在当前的activity上。
因此我们可以通过windowManager.addView方法添加视图在当前的activity上。
windowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG
4.不同activity共享一个悬浮窗
在开发过程中发现,通过activity获取的windowManager是会与当前的activity进行绑定,在其他activity页面去使用的话,是不成功的,看了源码发现,windowParams.token就是当前的activity,因此在每次切换activity的时候,需要重新设置下token为当前的activity即可。
windowManager =
activity?.getSystemService(Context.WINDOW_SERVICE) as WindowManager?
windowParams.token = activity?.window?.decorView?.windowToken
总结
具体的思路以及困难点都已写出来了,代码详情可以查看 FloatWindow