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

时间:2013-01-29 16:05:03

标签: android android-layout orientation

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

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

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

4 个答案:

答案 0 :(得分:23)

我尝试了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);

您可以在我发布的应用中看到我的成功:Force Dock Rotation

答案 1 :(得分: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);

答案 2 :(得分:12)

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

    在AndroidManifest.xml中
  1. Grant accesssystem settings (WRITE_SETTINGS)

    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    
  2. 导入Settings

    import android.provider.Settings;
    
  3. 确保Android screen auto-rotation已停用

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

    Settings.System.putInt(
        getContentResolver(),
        Settings.System.USER_ROTATION,
        Surface.ROTATION_0 //Or a different ROTATION_ constant
    );
    
  5. 请注意,即使您的应用未运行或已卸载,对USER_ROTATION的更改仍会存在。如果我没记错,用户可以通过手动禁用和启用自动旋转来重置此值。

答案 3 :(得分:2)

创建系统视图

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

选项

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

  1. 系统覆盖窗口(TYPE_SYSTEM_OVERLAY

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

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    
  2. Toast窗口(TYPE_TOAST

    无需许可,except on MIUI V8

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

  3. 说明

    1. 创建View
    2. 创建WindowManager.LayoutParams
      1. type设置为您在上面选择的值。
      2. 将其widthheight归零,以防止在重叠时无法正常运行的应用程序出现问题。 (例如,如果窗口位于其上,当您尝试启用辅助功能服务时,Android将不允许您按“确定”按钮。)
      3. screenOrientation设置为您想要的orientation value
    3. 实施例

      履行
      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;
          }
      
      }
      
      用法
      ScreenOrientationEnforcer screenOrientationEnforcer
          = new ScreenOrientationEnforcer(context);
      
      //Force screen orientation
      screenOrientationEnforcer.start();
      
      //Stop forcing screen orientation
      screenOrientationEnforcer.stop();
      

      缺点

      • 根据我的经验,如果您的应用崩溃或被杀,视图可能会持续存在。重启设备似乎可以解决这个问题。

      参考