本篇内容介绍了“Android WindowManger怎么实现桌面悬浮窗功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
如果想实现一个在桌面显示的悬浮窗,用Dialog
、PopupWindow
、Toast
等已经不能实现了,他们基本都是在Activity
之上显示的,如果想实现在桌面显示的悬浮窗效果,需要用到WindowManager
来实现了。
添加一个悬浮窗:
sys_view = new SmallWindowView(mContext); sys_view.setText("50%"); sys_view.setOnTouchListener(this); windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); int screenWidth = 0, screenHeight = 0; if (windowManager != null) { //获取屏幕的宽和高 Point point = new Point(); windowManager.getDefaultDisplay().getSize(point); screenWidth = point.x; screenHeight = point.y; layoutParams = new WindowManager.LayoutParams(); // layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; // layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.width = 200; layoutParams.height = 200; //设置type if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //26及以上必须使用TYPE_APPLICATION_OVERLAY @deprecated TYPE_PHONE layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; } //设置flags layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; layoutParams.gravity = Gravity.START | Gravity.TOP; //背景设置成透明 layoutParams.format = PixelFormat.TRANSPARENT; layoutParams.x = screenWidth; layoutParams.y = screenHeight / 2; //将View添加到屏幕上 windowManager.addView(sys_view, layoutParams); }
更新悬浮窗位置:
windowManager.updateViewLayout(sys_view, layoutParams);
关闭悬浮窗:
windowManager.removeView(sys_view);
通过上面的代码就可以实现一个桌面悬浮窗功能了。
注意:在6.0
以上,需要在Manifest.xml
中声明 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
权限并且在开启悬浮窗时动态判断权限,如果没有此权限需要跳到设置页面去设置。
1、添加悬浮窗: 通过Context.getSystemService(Context.WINDOW_SERVICE)
获得一个WindowManager
(以下简称VM), VM
是外界访问Window
的入口,Activity
、Dialog
、Toast
等其视图都是依附在Window
之上的,Window
是View
的直接管理者,VM
继承自ViewManager
,其添加、刷新、删除方法也是来自ViewManager
:
public interface ViewManager { public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); }
VM
有一个静态内部类WindowManager.LayoutParams
,Window
的各个属性在这个内部类中设置:
LayoutParams.TYPE 如果TargetSdkVersion<26
,那么可以直接使用LayoutParams.TYPE_PHONE
或者LayoutParams.TYPE_SYSTEM_ALERT
,在TargetSdkVersion>=26
时,TYPE_PHONE
和TYPE_SYSTEM_ALERT
都已经废弃了,需要使用TYPE_APPLICATION_OVERLAY
来标识TYPE
。
LayoutParams.FLAGS FLAGS
表示Window
的属性,通过FLAGS
可以控制Window
的显示特性,常用的几个特性: LayoutParams.FLAG_NOT_TOUCH_MODAL
: 使用了此标识,可以将点击事件传递到悬浮窗以外的区域,反之其他区域的Window
将接收不到事件。 LayoutParams.FLAG_NOT_FOCUSABLE
: 表示悬浮窗Window
不需要获取焦点,也不需要获取各种输入事件,事件会直接传递给下层的具有焦点的Window
LayoutParams.FLAG_SHOW_WHEN_LOCKED
: 此模式可以让Window
显示在锁屏的界面上
LayoutParams.FORMAT 悬浮窗Window的背景格式,一般设置成PixelFormat.TRANSPARENT
透明即可
LayoutParams.X & LayoutParams.Y 悬浮窗Window
在屏幕上的坐标值,可以根据X&Y
的值来刷新Window
在屏幕上的位置
LayoutParams.Width & LayoutParams.Height 悬浮窗Window
的宽度和高度
2、更新悬浮窗位置: 在View
的OnTouchEvent
中或OnTouch
中更新layoutParams.x
及layoutParams.y
的值并通过windowManager.updateViewLayout()
重新设置悬浮窗Window在屏幕中的位置,如下:
@Override public boolean onTouch(View v, MotionEvent event) { int mInScreenX = (int) event.getRawX(); int mInScreenY = (int) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = (int) event.getRawX(); mLastY = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE: layoutParams.x += mInScreenX - mLastX; layoutParams.y += mInScreenY - mLastY; mLastX = mInScreenX; mLastY = mInScreenY; windowManager.updateViewLayout(sys_view, layoutParams); break; case MotionEvent.ACTION_UP: break; } return true; }
3、删除悬浮窗: 删除比较简单,直接调用windowManager.removeView(view)
把view
从Window
中删除即可。
在6.0以上
使用时,需要动态申请该悬浮窗权限,如下:
//判断有没有悬浮窗权限,没有去申请 if(!Settings.canDrawOverlays(context)){ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName())); context.startActivityForResult(intent, REQUEST_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE: if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return; if (!WindowUtil.canOverDraw(this)) { toast("悬浮窗权限未开启,请在设置中手动打开"); return; } WindowController.getInstance().showThumbWindow(); break; } }
通过Settings.canDrawOverlays(context)
判断是否有悬浮窗权限,如果没有,跳转到设置页面去设置,并在onActivityResult ()
中得到申请结果,看似很完美,但在实际测试中,发现在8.0以上的手机上有问题,即使在设置中同意了权限,8.0的手机Settings.canDrawOverlays(context)
总是返回false
,不过在关闭页面重新调用此方法时,又返回的true
,感觉是有一定的延迟,google
了一下,发现别人同样遇到了这个问题,貌似已经给google
提交了bug
单。
“Android WindowManger怎么实现桌面悬浮窗功能”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。