前言:
最近在做的项目中有一个直播模块,直播模块中有一个最小化的功能,就是观众端观看直播的时候,可以选择最小化,在整个应用中有一个小窗口播放直播画面。在参考了微博、斗鱼直播等市面上主流的直播软件,发现它们都是通过悬浮窗(WindowManager)来实现最小化功能的。
1.悬浮窗权限
使用悬浮窗首先要在AndroidManifest.xml中配置悬浮窗权限。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
但是在MIUI等有些ROM中仅仅配置这个权限还不行,还需要用户手动去设置中开启悬浮窗权限。
对于不同ROM中判断悬浮窗权限是否开启,适配比较麻烦,后续单独以一篇来讲解。
2.创建悬浮窗
View mWindowView = LayoutInflater.from(context).inflate(R.layout.layout_live_window, null);
WindowManager mWindowManager=(WindowManager) context.getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams mWindowLP = new WindowManager.LayoutParams();
mWindowLP.format = PixelFormat.RGBA_8888;
mWindowLP.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
mWindowLP.gravity = Gravity.RIGHT | Gravity.BOTTOM;
mWindowLP.x = 0;
mWindowLP.y = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//Android O只能使用TYPE_APPLICATION_OVERLAY
mWindowLP.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
mWindowLP.type = WindowManager.LayoutParams.TYPE_PHONE;
}
mWindowLP.width = (int) DisplayUtil.dpToPx(mContext, 120);
mWindowLP.height = (int) DisplayUtil.dpToPx(mContext, 160);
//显示悬浮窗
mWindowManager.addView(mWindowView, mWindowLP);
移除悬浮窗
mWindowManager.removeView(mWindowView);
WindowManager.LayoutParams中的FLAG类型
FLAG_DIM_BEHIND 窗口之后的内容变暗
FLAG_BLUR_BEHIND 窗口之后的内容变模糊
FLAG_NOT_FOCUSABLE 不许获得焦点
FLAG_NOT_TOUCHABLE 不接受触摸屏事件。
当窗口可以获得焦点(没有设置 FLAG_NOT_FOCUSALBE 选项)时,仍然将窗口范围之外的点设备事件(鼠标、触摸屏)发送给后面的窗口处理。否则它将独占所有的点设备事件,而不管它们是不是发生在窗口范围内。
FLAG_KEEP_SCREEN_ON 当此窗口为用户可见时,保持设备常开,并保持亮度不变。
FLAG_LAYOUT_IN_SCREEN 窗口占满整个屏幕,忽略周围的装饰边框(例如状态栏)。此窗口需考虑到装饰边框的内容。
FLAG_LAYOUT_NO_LIMITS 允许窗口扩展到屏幕之外
FLAG_FULLSCREEN 窗口显示时,隐藏所有的屏幕装饰(例如状态条)。使窗口占用整个显示区域。
FLAG_FORCE_NOT_FULLSCREEN 此选项将覆盖FLAG_FULLSCREEN选项,并强制屏幕装饰(如状态条)弹出。
FLAG_DITHER 抖动。指 对半透明的显示方法。又称“点透”。图形处理较差的设备往往用“点透”替代Alpha混合。
FLAG_SECURE 不允许屏幕截图。
FLAG_SCALED 一种特殊模式,布局参数用于指示显示比例。
FLAG_IGNORE_CHEEK_PRESSES 当屏幕有可能贴着脸时,这一选项可防止面颊对屏幕造成误操作
FLAG_ALT_FOCUSABLE_IM 反转FLAG_NOT_FOCUSABLE选项。
如果同时设置了FLAG_NOT_FOCUSABLE选项和本选项,窗口将能够与输入法交互,允许输入法窗口覆盖;
如果FLAG_NOT_FOCUSABLE没有设置而设置了本选项,窗口不能与输入法交互,可以覆盖输入法窗口。
FLAG_WATCH_OUTSIDE_TOUCH 如果你设置了FLAG_NOT_TOUCH_MODAL,那么当触屏事件发生在窗口之外事,可以通过设置此标志接收到一个 MotionEvent.ACTION_OUTSIDE事件。注意,你不会收到完整的down/move/up事件,只有第一次down事件时可以收到 ACTION_OUTSIDE。
FLAG_SHOW_WHEN_LOCKED 当屏幕锁定时,窗口可以被看到。这使得应用程序窗口优先于锁屏界面。可配合FLAG_KEEP_SCREEN_ON选项点亮屏幕并直接显示在锁屏界面之前。可使用FLAG_DISMISS_KEYGUARD选项直接解除非加锁的锁屏状态。此选项只用于最顶层的全屏幕窗口。
FLAG_SHOW_WALLPAPER 请求系统墙纸显示在你的窗口后面。窗口必须是半透明的。
FLAG_TURN_SCREEN_ON 窗口一旦显示出来,系统将点亮屏幕,正如用户唤醒设备那样。
FLAG_DISMISS_KEYGUARD 解除锁屏。只有锁屏界面不是加密的才能解锁。如果锁屏界面是加密的,那么用户解锁之后才能看到此窗口,除非设置了FLAG_SHOW_WHEN_LOCKED选项。
FLAG_KEEP_SURFACE_WHILE_ANIMATING 锁屏界面淡出时,继续运行它的动画。
FLAG_COMPATIBLE_WINDOW 以原始尺寸显示窗口。用于在兼容模式下运行程序。
FLAG_SYSTEM_ERROR 用于系统对话框。设置此选项的窗口将无条件获得焦点。
以上是WindowManager基本的创建显示、移除。实际使用中一般会创建一个Manager管理类来管理WindowManager的
创建、移除。并且在Service中去通过Manager类来实现悬浮窗的创建、显示、移除。