如何检测屏幕从横向到横向旋转180度?

22

我看到有几个类似的问题,但都没有答案。

从纵向旋转到横向(无论向哪个方向),然后再切换回来,我们会得到有用的onConfigurationChanged()调用。

然而,当在横向模式下旋转180度时,不会调用onConfigurationChanged()。

我看到了使用OrientationEventListener的提及,但我觉得这似乎不太可靠,因为你可以快速地旋转而不触发显示方向更改。

我尝试添加布局更改侦听器,但没有成功。

因此,问题是如何可靠地检测到这种横向方向的更改?


我目前也遇到了同样的问题。你找到解决方法了吗? - Ifrit
我也遇到了同样的问题,你有解决方案吗?如果你找到了,请发帖告诉我。我已经在这个问题上浪费了一周的时间。 - Himanshu Mohan
@superuser的回复是正确的,请将其标记为已接受。 - Louis CAD
4个回答

15

当设备没有旋转/移动时,OrientationEventlistener不起作用。

我发现显示监听器是检测更改的更好方法。

     DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
        @Override
        public void onDisplayAdded(int displayId) {
           android.util.Log.i(TAG, "Display #" + displayId + " added.");
        }

        @Override
        public void onDisplayChanged(int displayId) {
           android.util.Log.i(TAG, "Display #" + displayId + " changed.");
        }

        @Override
        public void onDisplayRemoved(int displayId) {
           android.util.Log.i(TAG, "Display #" + displayId + " removed.");
        }
     };
     DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
     displayManager.registerDisplayListener(mDisplayListener, UIThreadHandler);

2
注意:这需要API Level 17+。 - lapis
为什么在设备没有旋转/移动时需要使用OrientationEventListener? - shaktiman_droid
我的应用需要提供最新的方向状态,但有时方向可能会通过调用API进行更改。最终我使用了一个线程来获取它的状态...确实没有更好的解决方案,因为这只适用于API 17+。 - superuser
4
这应该成为被接受的答案。 onDisplayChanged 仅在 getRotation() 更改时触发。 另一方面, OrientationEventListener 实时不断地触发,甚至在 getRotation() 更改之前就会触发,导致屏幕旋转值完全错误,当进行180度旋转时。 - 0101100101
在我的情况下,DisplayListener在Android TV Api 17上无法正常工作。有什么建议吗? - Aleksandr A

6
也许你应该在你的OrientationEventListener中添加一些逻辑代码,像这样:
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

OrientationEventListener orientationEventListener = new OrientationEventListener(this,
        SensorManager.SENSOR_DELAY_NORMAL) {
    @Override
    public void onOrientationChanged(int orientation) {

        Display display = mWindowManager.getDefaultDisplay();
        int rotation = display.getRotation();
        if ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && rotation != mLastRotation) {
            Log.i(TAG, "changed >>> " + rotation);

            // do something

            mLastRotation = rotation;
        }
    }
};

if (orientationEventListener.canDetectOrientation()) {
    orientationEventListener.enable();
}

为什么只有90度和270度?手机通常不能倒置,但平板电脑可以。同样的问题出现在从纵向旋转180度时。 - Oliv
2
小心这个答案!OrientationEventListener不是适用于180°方向变化的正确工具,因为它会在实时中不断触发,甚至在getRotation()改变之前就会触发!DisplayListener做得更好,因为它只在getRotation()改变时才会触发。 - 0101100101
@0101100101 非常正确,有时候即使OrientationEventListener说发生了旋转,实际上屏幕并没有旋转。 - user924
大家不要使用这个方法,因为它可能会导致延迟的方向更改或者在旋转时有时候方向不会改变,所以这种方法不能正确地告诉您应用程序的当前方向。 - user924

3
我使用这段代码使其适用于我的情况。
  OrientationEventListener mOrientationEventListener = new OrientationEventListener(mActivity)
  {
     @Override
     public void onOrientationChanged(int orientation)
     {
        if (orientation == ORIENTATION_UNKNOWN) return;

        int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
        switch (rotation) {
          case Surface.ROTATION_0:
             android.util.Log.i(TAG, "changed ROTATION_0 - " + orientation);
             break;
          case Surface.ROTATION_90:
             android.util.Log.i(TAG, "changed ROTATION_90 - " + orientation);
             break;
          case Surface.ROTATION_180:
             android.util.Log.i(TAG, "changed ROTATION_180 - " + orientation);
             break;
          case Surface.ROTATION_270:
             android.util.Log.i(TAG, "changed ROTATION_270 - " + orientation);
             break;
        }
        if ((rotation != mLastRotation) && (rotation & 0x1) == (mLastRotation & 0x1))
        {
           android.util.Log.i(TAG, "unhandled orientation changed >>> " + rotation);
        }
        mLastRotation = rotation;
     }
  };

  if (mOrientationEventListener.canDetectOrientation()){
     mOrientationEventListener.enable();
  }

2
小心这个答案!OrientationEventListener不是适用于180°方向变化的正确工具,因为它会在实时中不断触发,甚至在getRotation()改变之前就会触发!DisplayListener做得更好,因为它只在getRotation()改变时才会触发。 - 0101100101
大家不要使用这个方法,因为它可能会导致延迟的方向更改或者在旋转时有时候方向不会改变,所以这种方法不能正确地告诉您应用程序的当前方向。 - user924
更不用说在Android 9中,他们添加了新的按钮,允许用户更改应用程序的方向(或不更改),但这仍将触发旋转代码。 - 1800 INFORMATION

1

您仍然需要使用显示监听器类:Google推荐用它来处理从未锁定方向的180度设备旋转。您不能简单地将所有对onDisplayChanged的回调视为180度旋转。来自Google的更完整的实现展示了如何在onDisplayChanged回调期间从Display manager收集Display旋转,正如superuser所提到的。

/** DisplayManager to listen to display changes */
private val displayManager: DisplayManager by lazy {
    applicationContext.getSystemService(DISPLAY_SERVICE) as DisplayManager
}

/** Keeps track of display rotations */
private var displayRotation = 0

...

override fun onAttachedToWindow() {
    super.onAttachedToWindow()
    displayManager.registerDisplayListener(displayListener, mainLooperHandler)
}

override fun onDetachedFromWindow() {
    super.onDetachedFromWindow()
    displayManager.unregisterDisplayListener(displayListener)
}

private val displayListener = object : DisplayManager.DisplayListener {
    override fun onDisplayAdded(displayId: Int) {}
    override fun onDisplayRemoved(displayId: Int) {}
    override fun onDisplayChanged(displayId: Int) {
        val difference = displayManager.getDisplay(displayId).rotation - displayRotation
        displayRotation = displayManager.getDisplay(displayId).rotation

        if (difference == 2 || difference == -2) {
            createCaptureSession()
        }
    }
}

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