android悬浮窗的两种实现方案
16lz
2021-01-24
第一种实现,不依赖于activity,使用系统级别的WindowManager来添加view:
// 安卓8.0以上需要申请权限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !Settings.canDrawOverlays(BaseApplication.getInstance())){ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); startActivity(intent); return;}WindowManager windowManager = (WindowManager) BaseApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();// 设置宽高layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;// 设置背景透明layoutParams.format = PixelFormat.TRANSPARENT;// 设置屏幕左上角为起始点layoutParams.gravity = Gravity.LEFT | Gravity.TOP;// FLAG_LAYOUT_IN_SCREEN:将window放置在整个屏幕之内,无视其他的装饰(比如状态栏); FLAG_NOT_TOUCH_MODAL:不阻塞事件传递到后面的窗口layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;} else { // 设置窗体显示类型(TYPE_TOAST:与toast一个级别) layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;}// 设置布局弹出的动画layoutParams.windowAnimations = R.style.anim;// 添加视图View contentView = LayoutInflater.from(BaseApplication.getInstance()).inflate(R.layout.content_view, null);windowManager.addView(contentView, layoutParams);
第二种实现,在应用内实现悬浮窗,需要依赖activity,可通过反射机制获取当前顶部窗口:
/** * 获取顶部activity * @return */private Activity getTopActivity() { try { Class activityThreadClass = Class.forName("android.app.ActivityThread"); Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null); Field activitiesField = activityThreadClass.getDeclaredField("mActivities"); activitiesField.setAccessible(true); Map activities = (Map) activitiesField.get(activityThread); for (Object activityRecord : activities.values()) { Class activityRecordClass = activityRecord.getClass(); Field pausedField = activityRecordClass.getDeclaredField("paused"); pausedField.setAccessible(true); if (!pausedField.getBoolean(activityRecord)) { Field activityField = activityRecordClass.getDeclaredField("activity"); activityField.setAccessible(true); Activity activity = (Activity) activityField.get(activityRecord); return activity; } } } catch (Exception e) { e.printStackTrace(); } return null;}
// 在顶部窗口上面添加悬浮窗Activity activity = getTopActivity();View rootView = activity.getWindow().getDecorView().getRootView();ViewGroup contentView = rootView.findViewById(android.R.id.content);View floatView = LayoutInflater.from(BaseApplication.getInstance()).inflate(R.layout.float_view, null);// 添加视图contentView.addView(floatView);// 添加动画floatView.startAnimation(AnimationUtils.loadAnimation(floatView.getContext(), R.anim.anim));
更多相关文章
- android 一些常用控件属性设置
- android 日历组件(CalendarView)
- Android学习之保持屏幕常亮的几种方法
- 深入理解LayoutInflater
- Android(安卓)3.0 r1中文API文档(103) —— InputMethodManager
- Android(安卓)简单封装一个精美、好用的菜单型PopupWindow
- Android(安卓)中sp、dp、px转换,以及获取手机屏幕宽高
- ConstraintLayout (约束布局)属性详情
- Android实现随屏幕旋转的TextView