安卓中的WindowManager是什么?

70

我尝试搜索,但没有直接和/或清晰的答案。

开发者网站的定义也不明确:

应用程序用来与窗口管理器交互的接口。 使用Context.getSystemService(Context.WINDOW_SERVICE)获取其中之一。

有能力用通俗易懂的英语解释一下是什么吗?

如何使用它创建一个浮动对象,使其在多个活动之间保持不变,即使我从一个活动到另一个活动?

3个回答

155
Android WindowManager是一个系统服务,负责管理窗口的z轴排序列表,哪些窗口可见以及它们如何在屏幕上布局。除其他外,当打开或关闭应用程序或旋转屏幕时,它会自动执行窗口过渡和动画。
每个Activity都有一个Window用于在屏幕上显示其内容。当您在Activity上调用setContentView时,它会将该视图附加到Activity的默认窗口。默认窗口填充整个屏幕,因此您的Activity窗口会隐藏任何其他Activity——WindowManager将显示位于顶部的窗口。因此,通常情况下您不必担心窗口-您只需创建一个Activity,Android将为您完成其余工作。
但是,如果您想要做一些不寻常的事情,例如创建不占据整个屏幕的浮动窗口,则需要与WindowManager进行交互。如果您想要创建一个浮动窗口,该窗口在其他应用程序前可见,则不能使用Activity,因为当另一个应用程序成为前台应用程序时,您的Activity将停止,并且其窗口将被隐藏或销毁。相反,您需要从后台服务中显示窗口。例如:
WindowManager.LayoutParams p = new WindowManager.LayoutParams(
    // Shrink the window to wrap the content rather than filling the screen 
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.WRAP_CONTENT,
    // Display it on top of other application windows, but only for the current user
    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
    // Don't let it grab the input focus
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
    // Make the underlying application window visible through any transparent parts
    PixelFormat.TRANSLUCENT);

// Define the position of the window within the screen
p.gravity = Gravity.TOP | Gravity.RIGHT;
p.x = 0;
p.y = 100;

WindowManager windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
windowManager.addView(myView, p);

为了使此功能正常工作,您需要将以下权限添加到您的AndroidManifest.xml中。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

@simonp 我正在使用两个Windomanager对象,但它们似乎彼此冲突。我无法正确调用其中一个的ontouch,直到我删除另一个为止。你知道如何解决这个问题吗? - Dania
所有WindowManager.addView都需要权限,还是只有设置了TYPE_APPLICATION_OVERLAY标志的那个? - Elye

7

针对 Android API 版本大于23的情况,需要在运行时请求 android.permission.SYSTEM_ALERT_WINDOW 权限。此外,在 Android API 26 中,TYPE_SYSTEM_ERROR 和其他少数类型已经被弃用。以下是解决方法:

public void showWindowManager() {
    if (requestPermission()) {
        return;
    }

    WindowManager.LayoutParams p =
            new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    Build.VERSION.SDK_INT > Build.VERSION_CODES.O
                            ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
                            : WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    PixelFormat.TRANSLUCENT);


    final WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
    LayoutInflater layoutInflater =
            (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
    final View popupView = layoutInflater.inflate(R.layout.window_manager_layout, null);
    windowManager.addView(popupView, p);

    // dismiss windowManager after 3s
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            windowManager.removeView(popupView);
        }
    }, 3000);
}

@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
        if (Settings.canDrawOverlays(this)) {
            showWindowManager();
        }
    }
}

public boolean requestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
            return true;
        }
    }
    return false;
}

2

窗口管理器组织屏幕并处理应该放置在哪里以及如何分层。

以下是一个漂浮对象的优秀开源示例。 漂浮对象示例


我只想在我的应用程序打开(对用户可见)时才实现这一点,通过上述开源方案是否可能? - tony9099
当然,在您的应用程序的OnPause方法中停止服务。当然,在OnResume中再次启动服务。 - Pete
我成功地完成了这个。非常感谢。这个项目很容易使用。不过,是否可以使用自定义布局而不是球?例如,显示一个带有图像X的文本(每次都不同)? - tony9099
1
没问题。关于自定义布局我不太确定,但我相信这是可能的。你可以将资源设置为TextView而不是ImageView,然后通过代码进行处理。 - Pete
1
它可以工作!但是,当我尝试从WindowManager中删除一个视图windowManager.removeView()时,会在移除视图期间出现一些闪烁。如何避免这种情况? - Chaitanya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接