Android悬浮窗详解(android实现可自由移动)

一、悬浮窗简介

悬浮窗是一个可以浮在其他应用界面之上的视图,常常作为与用户交互的工具,允许用户快速地执行某些操作,同时也可以显示一些信息。悬浮窗广泛应用于游戏、社交和工具类应用中,在手机屏幕较小的情况下充分利用空间,提升用户体验。

悬浮窗不同于普通的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,就可以让悬浮窗获得焦点,接收用户的键盘输入。

四、总结

悬浮窗是一种常用的交互手段,可以提升用户体验,但是在实现时需要处理一些问题,如权限、生命周期和焦点等。通过正确地处理这些问题,可以实现良好的悬浮窗体验。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注