android - 如何使我的全屏覆盖在方向更改后保持全屏?

标签 android android-layout android-service android-view android-fullscreen

我正在制作一个应用程序,可以创建在屏幕上四处走动的小 Sprite 动画。

我有一个主要 Activity ,带有一个“启动服务”按钮。这将启动一个服务,该服务(在 onCreate() 中)创建一个全屏 View 并将其附加到根窗口管理器。

这部分工作完美。它会填满屏幕,您可以离开应用程序,动画仍然会在所有内容上可见。

initial render is fine

旋转设备时出现问题。

view does not rotate with device

Sprite 已移动到屏幕中间,但这是一个不相关的问题;这里重要的是黑色边界框——这个框向你展示了我可以在其中绘制的 Canvas ,它需要填满整个屏幕

View 仍然是纵向模式,即使所有其他布局似乎都已正确更新。


部分问题来 self 指定 View 尺寸的方式。我使用标志来指定“全屏”,但这确实没有设置 View 的宽度高度以匹配屏幕尺寸。因此我必须在启动时手动设置它们。

我不知道如何在创建 View 后更新 View 的宽度和高度,但我觉得我需要这样做,因为 View 的尺寸决定了 Canvas 的尺寸。

我的服务像这样创建 View :

public class WalkerService extends Service {
    private WalkerView view;

    @Override
    public void onCreate() {
        super.onCreate();

        final WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);

        final DisplayMetrics metrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);

        view = new WalkerView(this); // extends SurfaceView
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, // TYPE_SYSTEM_ALERT is denied in apiLevel >=19
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT
        );
        view.setFitsSystemWindows(false); // allow us to draw over status bar, navigation bar

        // here I _manually_ set the dimensions, because otherwise it defaults to a square (something like 1024x1024)
        params.width = metrics.widthPixels;
        params.height = metrics.heightPixels;

        wm.addView(view, params);
    }
}

我试过监听方向变化,并在发生这种情况时旋转 View :

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    view.setRotation(
            newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
                    ? 90.0f
                    : 0.0f
    );
}

但是 setRotation() 似乎并没有影响我的 View 的 widthheight,它们也没有改变旋转的角度 Canvas 被渲染。


我是否从根本上误解了如何创建全屏覆盖?无论方向如何(即使我的应用不是 Activity 应用),我如何保持在整个屏幕上绘图的能力?

也许这与我将我的 View 附加到窗口服务的窗口管理器这一事实有关——也许这意味着我的 View 有一个奇怪的父 View (我可以想象 Root View 可能不会受到方向的影响,或者没有为 children 定义的边界来拉伸(stretch)以填充)。

完整的源代码是 public on GitHub以防我在这里遗漏了任何有用的信息。

WalkerView.java 可能特别相关,所以 here it is .

最佳答案

我被前一个问题的答案误导了 "How to create always-top fullscreen overlay activity in Android" .也许它适用于较旧的 API 级别?我使用的是 API 级别 24。

该特定答案推荐:

final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.FLAG_FULLSCREEN,
    WindowManager.LayoutParams.FLAG_FULLSCREEN,
    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
    PixelFormat.TRANSLUCENT
);

这里有一个问题。 WindowManager.LayoutParams 存在的构造函数如下:

enter image description here

因此 WindowManager.LayoutParams.FLAG_FULLSCREEN 标志被用作 int wint h显式值。这可不行!


我发现全屏覆盖的正确构造如下:

final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, // TYPE_SYSTEM_ALERT is denied in apiLevel >=19
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_FULLSCREEN,
    PixelFormat.TRANSLUCENT
);

这意味着我们不再显式指定宽度和高度。布局完全依赖于我们的标志。

是的,WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 仍然是必需的标志;如果你想绘制状态栏等装饰,这是必要的。

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY 应在 API 级别 >=19 中使用,而不是 TYPE_SYSTEM_ALERT


附注(如果您正在阅读本文,您可能正在尝试制作全屏叠加层):

您的 list 将需要以下权限(解释 here):

<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

我的理解是 SYSTEM_ALERT_WINDOW 是所需的实际权限,但还需要 ACTION_MANAGE_OVERLAY_PERMISSION:它允许您在运行时请求用户授予 SYSTEM_ALERT_WINDOW 特权。

关于android - 如何使我的全屏覆盖在方向更改后保持全屏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41455138/

相关文章:

java - 无法根据从数据库中检索到的值设置微调器位置

android - 从 BottomSheet 顶部移除多余空间

java - 我怎样才能杀死android中的其他前台 Activity ?

android - 如何访问回收站 View 中项目的查看器?

android - 将 ImageView 背景设置为位图

java - Android - 更改所有 Android 版本的应用程序语言

android - 使用服务流式传输音频

Android 本地通知有时不会显示

android - GMail 中的 ListView 行标记

android - 创建一个持续轮询 REST API 数据的 Android 后台服务