如何在Android中全局强制屏幕方向?

kag*_*ick 16 android orientation android-layout

有许多应用程序可以强制屏幕旋转.即使应用程序明确希望以其他方向查看,它们也能正常工作.现在我正在禁用加速度计旋转系统设置并设置我的首选方向.应用仍然可以覆盖此.

以下是能够覆盖应用程序请求方向的应用程序之一:

https://play.google.com/store/apps/details?id=nl.fameit.rotate&hl=en

小智 24

我尝试过kagronick的答案,但无法使其发挥作用.搞砸了一下后,我最终使用系统覆盖窗口工作,并删除了我发现的LayoutParams,这些都是不必要的.这是我的最终解决方案:

orientationChanger = new LinearLayout(this);
// Using TYPE_SYSTEM_OVERLAY is crucial to make your window appear on top
// You'll need the permission android.permission.SYSTEM_ALERT_WINDOW
WindowManager.LayoutParams orientationLayout = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0, PixelFormat.RGBA_8888);
// Use whatever constant you need for your desired rotation
orientationLayout.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;

WindowManager wm = (WindowManager) this.getSystemService(Service.WINDOW_SERVICE);
wm.addView(orientationChanger, orientationLayout);
orientationChanger.setVisibility(View.VISIBLE);
Run Code Online (Sandbox Code Playgroud)

您可以在我发布的应用程序中看到我的成功基于此:Force Dock Rotation.

  • 在进一步调查时,似乎您的上述代码在从服务运行时工作正常,但在从活动运行时则无效.也许它与使用的Context有关.(我不擅长Android,所以我不知道.) (2认同)

kag*_*ick 13

这可以通过创建隐藏的系统对话框来完成.它是一种黑客,但它疯狂到可以工作.

    wm = (WindowManager) content.getSystemService(Service.WINDOW_SERVICE);

    orientationChanger = new LinearLayout(content);
    orientationChanger.setClickable(false);
    orientationChanger.setFocusable(false);
    orientationChanger.setFocusableInTouchMode(false);
    orientationChanger.setLongClickable(false);

    orientationLayout = new WindowManager.LayoutParams(
            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
            windowType, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.RGBA_8888);

    wm.addView(orientationChanger, orientationLayout);
    orientationChanger.setVisibility(View.GONE);

    orientationLayout.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    wm.updateViewLayout(orientationChanger, orientationLayout);
    orientationChanger.setVisibility(View.VISIBLE);
Run Code Online (Sandbox Code Playgroud)


Sam*_*Sam 12

另外,您还可以全局更改屏幕方向,而不必在不受支持的应用程序中强制它.(我知道这个问题是关于覆盖应用程序的首选项,但这仍然有用且主要是相关信息.)

  1. 在AndroidManifest.xml中授予系统设置(WRITE_SETTINGS)的访问权限

    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    
    Run Code Online (Sandbox Code Playgroud)
  2. 进口 Settings

    import android.provider.Settings;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 确保禁用Android屏幕自动旋转

    Settings.System.putInt(
        getContentResolver(),
        Settings.System.ACCELEROMETER_ROTATION,
        0
    );
    
    Run Code Online (Sandbox Code Playgroud)
  4. 设置USER_ROTATION为所需的设置,该设置应该是ROTATION_常量之一.这些值表示设备自然方向的屏幕旋转,可以是横向或纵向.

    Settings.System.putInt(
        getContentResolver(),
        Settings.System.USER_ROTATION,
        Surface.ROTATION_0 //Or a different ROTATION_ constant
    );
    
    Run Code Online (Sandbox Code Playgroud)

请注意,USER_ROTATION即使您的应用未运行或已卸载,更改仍会保留.如果我没记错,用户可以通过手动禁用和启用自动旋转来重置此值.


Sam*_*Sam 5

创建系统视图

创建一个View始终显示在其他应用程序之上的不可见对象。View可以指定自己的方向首选项,因此视图的方向可用于覆盖基础视图和应用程序的方向。

选项

我知道您可以使用几种不同的视图类型来实现此目的,每种视图类型都有其自身的缺点。

  1. 系统叠加窗口 ( TYPE_SYSTEM_OVERLAY)

    需要SYSTEM_ALERT_WINDOW许可。(将以下内容添加到AndroidManifest.xml。)

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    
    Run Code Online (Sandbox Code Playgroud)
  2. 吐司窗口 ( TYPE_TOAST)

    无需许可,MIUI V8 除外

    不会在某些窗口类型上显示,因此它们的方向可能不会受到影响:

指示

  1. 创建一个View
  2. 创建一个WindowManager.LayoutParams
    1. 设置type为您在上面选择的值。
    2. 将其归零widthheight以防止应用程序重叠时无法运行的问题。(例如,当您尝试启用辅助功能服务(如果其顶部有一个窗口)时,Android 不会让您按“确定”按钮。)
    3. 将其设置screenOrientation为您想要的任何方向值

例子

执行
public class ScreenOrientationEnforcer {

    private final View view;
    private final WindowManager windows;

    public ScreenOrientationEnforcer(Context context) {
        windows = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        view = new View(context);
    }

    public void start() {
        WindowManager.LayoutParams layout = generateLayout();
        windows.addView(view, layout);
        view.setVisibility(View.VISIBLE);
    }

    public void stop() {
        windows.removeView(view);
    }

    private WindowManager.LayoutParams generateLayout() {
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();

        //So we don't need a permission or activity
        //Note that this won't work on some devices running MIUI
        layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;

        //Just in case the window type somehow doesn't enforce this
        layoutParams.flags =
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        //Prevents breaking apps that detect overlying windows enabling
        //(eg UBank app, or enabling an accessibility service)
        layoutParams.width = 0;
        layoutParams.height = 0;

        //Try to make it completely invisible
        layoutParams.format = PixelFormat.TRANSPARENT;
        layoutParams.alpha = 0f;

        //The orientation to force
        layoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;

        return layoutParams;
    }

}
Run Code Online (Sandbox Code Playgroud) 用法
ScreenOrientationEnforcer screenOrientationEnforcer
    = new ScreenOrientationEnforcer(context);

//Force screen orientation
screenOrientationEnforcer.start();

//Stop forcing screen orientation
screenOrientationEnforcer.stop();
Run Code Online (Sandbox Code Playgroud)

缺点

  • 根据我的经验,如果您的应用程序崩溃或被终止,该视图可能会持续存在。重新启动设备似乎可以解决此问题。

参考