一、悬浮窗简介
悬浮窗是一个可以浮在其他应用界面之上的视图,常常作为与用户交互的工具,允许用户快速地执行某些操作,同时也可以显示一些信息。悬浮窗广泛应用于游戏、社交和工具类应用中,在手机屏幕较小的情况下充分利用空间,提升用户体验。 悬浮窗不同于普通的View,它需要特殊的权限和设置才能正常显示。在Android 8.0及以上的系统版本中,需要动态请求悬浮窗权限才能显示悬浮窗。在Android系统版本低于8.0的手机上,悬浮窗权限默认开启,但需要在应用的manifest文件中声明该权限。
二、实现悬浮窗的方法
1. 使用系统API
Android提供了WindowManager类来管理窗口,通过创建一个带有TYPE_SYSTEM_ALERT
类型的WindowManager.LayoutParams
对象并将其添加到WindowManager中即可实现一个基本的悬浮窗。具体实现步骤如下:
// 1. 创建窗体布局
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayoutParams = new WindowManager.LayoutParams();
mLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
mLayoutParams.format = PixelFormat.TRANSPARENT;
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.x = 0;
mLayoutParams.y = 0;
// 2. 将窗体布局添加到WindowManager中
mWindowManager.addView(mFloatingView, mLayoutParams);
其中,type
参数设置为TYPE_SYSTEM_ALERT
,表示以系统级别的方式显示视图。format
参数设置为TRANSPARENT
,使窗体背景为空,FLAG_NOT_TOUCH_MODAL
和FLAG_NOT_FOCUSABLE
参数表示窗口不会影响其他应用的触摸事件和聚焦事件,width
和height
参数设置为WRAP_CONTENT
,表示视图宽度和高度会自适应内容大小。
2. 使用第三方库
除了使用系统API实现悬浮窗外,也可以使用第三方库来简化开发流程。比如,可以使用GitHub上的FloatingView库实现悬浮窗。这个库提供了很多悬浮窗功能,如动画效果、自定义样式等。
使用FloatingView库也很简单,只需要在build.gradle
文件中添加以下依赖即可:
dependencies {
implementation 'com.github.pinguo-zhouwei:FloatingView:latest.release'
}
然后在代码中创建FloatingView,并添加到视图中即可:
FloatingViewManager mFloatingViewManager = new FloatingViewManager(this);
FloatingView mFloatingView = new FloatingViewManager(getApplicationContext()).addView(R.layout.floating_view, new FloatingViewManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT), new FloatingViewManager.ViewStateListener() {
@Override
public void onPositionUpdate(int x, int y) {
// 悬浮窗移动时的回调
}
@Override
public void onDismiss() {
// 悬浮窗关闭时的回调
}
@Override
public void onShow() {
// 悬浮窗显示时的回调
}
});
mFloatingViewManager.addView(mFloatingView);
三、悬浮窗的常见问题及解决方法
1. 悬浮窗权限问题
在Android 8.0及以上的系统版本中,需要动态申请悬浮窗权限才能显示悬浮窗。如果没有权限,将无法在应用外部显示悬浮窗。可以通过以下代码来动态申请权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(MainActivity.this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE);
}
}
其中,ACTION_MANAGE_OVERLAY_PERMISSION
是打开悬浮窗设置页面的常量,Uri.parse("package:" + getPackageName())
是一个URI地址,打开设置页面时会将此参数传递给系统。
2. 悬浮窗生命周期问题
当应用退出时,悬浮窗应该被关闭,并释放相应的资源,以防止内存泄漏。可以通过以下代码来实现生命周期管理:
@Override
protected void onDestroy() {
super.onDestroy();
if (mWindowManager != null) {
mWindowManager.removeView(mFloatingView);
}
}
当Activity销毁时,会调用onDestroy()
方法,此时需要将悬浮窗从WindowManager中移除,防止悬浮窗在应用退出后还显示在屏幕上。
3. 悬浮窗焦点问题
在Android系统中,悬浮窗默认不能获得焦点,也就无法接收用户的键盘输入。可以通过以下代码来设置悬浮窗获得焦点:
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
将FLAG_NOT_FOCUSABLE
改为FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE
,就可以让悬浮窗获得焦点,接收用户的键盘输入。
四、总结
悬浮窗是一种常用的交互手段,可以提升用户体验,但是在实现时需要处理一些问题,如权限、生命周期和焦点等。通过正确地处理这些问题,可以实现良好的悬浮窗体验。