更改方向后如何使我的全屏覆盖图保持全屏显示? [英] How do I make my full-screen overlay remain full-screen after orientation changes?

查看:110
本文介绍了更改方向后如何使我的全屏覆盖图保持全屏显示?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



这部分工作正常。它会填满整个屏幕,您可以离开该应用程序,并且动画仍然可以在所有内容上看到。





旋转设备时出现问题。





精灵已经移到屏幕中间,但这是一个无关紧要的问题。这里重要的是黑暗的边界框-此框显示允许我绘制的画布,它需要填满整个屏幕



即使所有其他布局似乎都已正确更新,该视图仍为纵向模式。






部分问题来自从我如何指定视图的尺寸。我使用标志来指定全屏,但这并没有设置视图的宽度高度以匹配屏幕尺寸。因此,我不得不在启动时手动设置它们。



我不知道创建视图后更新视图的宽度和高度的方法,但是我觉得我需要,因为视图的尺寸决定了画布的尺寸。



我的服务创建的视图如下:

 公共类WalkerService扩展了服务{
私有WalkerView视图;

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

最终的WindowManager wm =(WindowManager)getSystemService(WINDOW_SERVICE);

最终的DisplayMetrics指标= new DisplayMetrics();
wm.getDefaultDisplay()。getMetrics(metrics);

view = new WalkerView(this); //扩展SurfaceView
最终的WindowManager.LayoutParams参数= new WindowManager.LayoutParams(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,/ / TYPE_SYSTEM_ALERT在apiLevel> = 19
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT
)中被拒绝;
view.setFitsSystemWindows(false); //允许我们绘制状态栏,导航栏

//在这里,我_manually_设置了尺寸,因为否则它默认为正方形(类似1024x1024)
params.width = metrics .widthPixels;
params.height = metrics.heightPixels;

wm.addView(view,params);
}
}

我尝试收听方向更改,然后旋转查看何时发生:

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

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

但是 setRotation()似乎并没有影响我的视图的宽度高度,它们也没有改变画布的角度






我是从根本上误解了如何创建全屏覆盖图?



也许与事实有关,我如何才能保持在整个屏幕上绘制的能力,而不必考虑方向(甚至当我的应用不是活动应用时)?我将我的视图附加到Window Service的窗口管理器中-也许这意味着我的视图具有一个奇怪的父视图(我可以想象,根视图可能不会受到方向的影响,或者将没有定义的边界供孩子拉伸填充) 。



完整的源代码是



因此 WindowManager.LayoutParams.FLAG_FULLSCREEN 标志用作<$> <$>的显式值c $ c> int w 和 int h






我发现全屏覆盖的正确构造就像这样:

  final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,// TYPE_SYSTEM_ALERT在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






奖金注意事项(如果您正在阅读此书,则可能正在尝试全屏覆盖):



您的清单将需要以下权限(说明< a href = https://stackoverflow.com/a/34061521/5257399>在这里):

 <使用权限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 特权。


I am making an app that creates tiny sprite animations that walk around your screen.

I have a main activity, with a button "start service". This starts a service, which (in onCreate()) creates a full-screen view and attaches it to the root window manager.

This part works perfectly. It fills the screen, and you can leave the app, and the animations will still be visible over everything.

The problem emerges when you rotate the device.

Sprites have moved to the middle of the screen, but this is an unrelated issue; the important thing here is the dark bounding box — this box shows you the canvas I am allowed to draw into, and it needs to fill the whole screen

The view is still portrait-mode, even though all other layouts seem to have updated correctly.


Part of the problem comes from how I have specified the dimensions of the view. I used flags to specify "full screen", but this did not set the view's width and height to match the screen's dimensions. Thus I had to set those manually at startup.

I don't know a way to update the width and height of the view once the view is created, but I feel that I need to, since the dimensions of the view determine the dimensions of the canvas.

My service creates the view like so:

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);
    }
}

I have tried listening for orientation changes, and rotating the view when that happens:

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

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

But setRotation() didn't seem to affect width and height of my view, nor did they change the angle at which the canvas was rendered.


Am I fundamentally misunderstanding how to create a full-screen overlay? How can I maintain the ability to draw over the entire screen, regardless of orientation (and even when my app is not the active app)?

Maybe it's related to the fact that I attach my view to the Window Service's window manager — perhaps this means my view has an odd parent (I could imagine that maybe the root view would not be affected by orientation, or would have no defined boundaries for children to stretch to fill).

Full source code is public on GitHub in case I've omitted any useful information here.

WalkerView.java may be particularly relevant, so here it is.

解决方案

I was misled by the answer to a previous question "How to create always-top fullscreen overlay activity in Android". Maybe it worked for an older API level? I'm using API level 24.

That particular answer had recommended:

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
);

There is a problem with this. The constructors that exist for WindowManager.LayoutParams are as follows:

So the WindowManager.LayoutParams.FLAG_FULLSCREEN flag gets used as an explicit value for int w and int h. This is no good!


I found that the correct construction for a full-screen overlay is like so:

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
);

This means we no longer explicitly specify a width and height. The layout relies entirely on our flags instead.

Yes, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN is a required flag still; it is necessary if you want to draw over decorations such as the status bar.

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY should be used instead of TYPE_SYSTEM_ALERT in API level >=19.


Bonus notes (if you're reading this, you're probably trying to make a full-screen overlay):

Your manifest will need the following permissions (explanation here):

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

My understanding is that SYSTEM_ALERT_WINDOW is the actual permission required, but that ACTION_MANAGE_OVERLAY_PERMISSION is needed also: it lets you request at runtime that the user grant the SYSTEM_ALERT_WINDOW privilege.

这篇关于更改方向后如何使我的全屏覆盖图保持全屏显示?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆