如何在运行时锁定屏幕方向

109

是否有一种在运行时锁定屏幕方向的方式?比如,如果用户当前处于横屏状态并切换菜单选项,则我希望允许用户将屏幕锁定为横屏。

7个回答

142
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

在一个活动中调用这个方法,将会把它锁定为横屏模式。在ActivityInfo类中查找其他标志,你可以将其锁定为竖屏或者设置为传感器/滑动驱动。

更多信息请参考:http://www.devx.com/wireless/Article/40792


14
好的,谢谢。这很有效。那将获得当前方向。 getResources().getConfiguration().orientation - Jared
7
小心!您需要区分getConfiguration()返回的内容和setRequestedOrientation想要的内容-请参阅下面的答案以获取详细信息。 - Andy Weinstein
这种方法存在问题。请确保仔细阅读此答案的评论。 - Bugs Happen
但它为所有活动设置相同的方向,是否有其他方法可以更改方向? - silverFoxA

111

要注意getConfiguration返回值与setRequestedOrientation想要的值之间的差异 - 它们都是int类型,但来自不同的常量定义。

下面介绍如何锁定当前方向,同时允许180度翻转。

int currentOrientation = getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
else {
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}

13
如果用户在设置中禁用了屏幕旋转,你可能更喜欢使用SCREEN_ORIENTATION_USER_LANDSCAPE,因为它不允许进行180度的翻转。同样,在切换回自由旋转时,SCREEN_ORIENTATION_USER比SCREEN_ORIENTATION_SENSOR更好,因为后者即使设置不允许,也允许自由旋转。 - Steve Waring
太棒了!需要补充一点,当您切换到反向方向时,重新配置不会发生。至少在我测试过的设备上是这样。如果您想在某些对话框显示等情况下停止重新配置,了解这一点非常重要。 - sberezin
传感器没有锁定! - user924

54

此功能适用于具有反向竖屏和反向横屏的设备。

锁定方向:

    int orientation = getActivity().getRequestedOrientation();
    int rotation = ((WindowManager) getActivity().getSystemService(
            Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
    switch (rotation) {
    case Surface.ROTATION_0:
        orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        break;
    case Surface.ROTATION_90:
        orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
        break;
    case Surface.ROTATION_180:
        orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
        break;
    default:
        orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
        break;
    }

    getActivity().setRequestedOrientation(orientation);

解锁方向:

   getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

5
获取旋转信息 "获取屏幕从其“自然”方向的旋转信息。" 来源。因此,在手机上,表示 ROTATION_0 为纵向是正确的,但在平板电脑上,其“自然”方向很可能是横向,ROTATION_0 应返回横向而不是纵向。请注意,本文中的"portrait"指纵向,"landscape"指横向。 - jp36
@jp36,我在Nexus 7上进行了测试,它的自然方向与手机相同。感谢您在一个更大的平板电脑上进行测试(我没有)。 - pstoppani
1
正如jp36所说,它在自然横向方向的平板电脑上无法工作! - DominicM
我们如何在设备上测试反向纵向模式? - AndyBoy

28

我似乎遇到了类似的情况。我想支持任何方向,但在工作流程的某个点之后需要保留当前方向。我的解决方法是:

进入受保护工作流程时:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
在受保护的工作流程结束时:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);

2
这并没有解决OQ的问题,至少在Android >= 16上是如此。setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)可能会将设备设置为横向模式,即使它原本是竖向的,而问题是关于锁定给定方向的方向。 - greg7gkb
5
对我来说,将其设置为“nosensor”会使我回到肖像模式,如果我在横向模式下。我使用了“SCREEN_ORIENTATION_LOCKED”,这对我很有效。 - Jimmar
2
@JiMMaR SCREEN_ORIENTATION_LOCKED是Android >= 18的最佳方式。但是,如果您的目标版本较低,则无法使用该方法。我建议使用jp36下面的答案。 - Patrick Boos

27

对于 @pstoppani 的回答,这里提供了支持平板电脑的替代方案(和 @pstoppani 的回答一样,这仅适用于设备版本 >2.2)
- 在 Samsung Galaxy SIIISamsung Galaxy Tab 10.1 上已进行测试。

public static void lockOrientation(Activity activity) {
    Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    int rotation = display.getRotation();
    int tempOrientation = activity.getResources().getConfiguration().orientation;
    int orientation = 0;
    switch(tempOrientation)
    {
    case Configuration.ORIENTATION_LANDSCAPE:
        if(rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90)
            orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
        else
            orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
        break;
    case Configuration.ORIENTATION_PORTRAIT:
        if(rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_270)
            orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        else
            orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
    }
    activity.setRequestedOrientation(orientation);
}

谢谢,这个代码很好用,但我不理解为什么要用“||”来检查 rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90,以及为什么要用 rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_270 来检查。所以我有两个疑问:第一,为什么在第二个情况下要使用 ROTATION_0 而不是 ROTATION_180;另一个疑问是为什么要将 0 度与 90 度进行比较而不是 180 度? - AndyBoy
@AndyBoy 这与设备的默认方向有关。通常手机的默认方向是竖屏,这意味着旋转返回零表示竖屏,但某些平板电脑的默认方向是横屏,这意味着旋转返回零表示横屏。因此,不同的 || 检查基于设备报告的横屏和竖屏处理两种可能的默认方向。 - jp36

6

这是我的代码,你可以使用其中一种方法锁定屏幕,完成任务后再使用unlockOrientation解锁:

/** Static methods related to device orientation. */
public class OrientationUtils {
    private OrientationUtils() {}

    /** Locks the device window in landscape mode. */
    public static void lockOrientationLandscape(Activity activity) {
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }

    /** Locks the device window in portrait mode. */
    public static void lockOrientationPortrait(Activity activity) {
    activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

    /** Locks the device window in actual screen mode. */
    public static void lockOrientation(Activity activity) {
        final int orientation = activity.getResources().getConfiguration().orientation;
        final int rotation = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();

        // Copied from Android docs, since we don't have these values in Froyo 2.2
        int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
        int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;

        // Build.VERSION.SDK_INT <= Build.VERSION_CODES.FROYO
        if (!BuildVersionUtils.hasGingerbread()) {
            SCREEN_ORIENTATION_REVERSE_LANDSCAPE = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
            SCREEN_ORIENTATION_REVERSE_PORTRAIT = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        }

        if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90){
            if (orientation == Configuration.ORIENTATION_PORTRAIT){
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            }
            else if (orientation == Configuration.ORIENTATION_LANDSCAPE){
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            }
        }
        else if (rotation == Surface.ROTATION_180 || rotation == Surface.ROTATION_270) 
        {
            if (orientation == Configuration.ORIENTATION_PORTRAIT){
                activity.setRequestedOrientation(SCREEN_ORIENTATION_REVERSE_PORTRAIT);
            }
            else if (orientation == Configuration.ORIENTATION_LANDSCAPE){
                activity.setRequestedOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
            }
        }
    }

    /** Unlocks the device window in user defined screen mode. */
    public static void unlockOrientation(Activity activity) {
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
    }

}

0

这是@pstoppani上面回答的Xamarin转换版本。

注意:这是用于Fragment的,如果在Activity中使用,请将Activity.替换为this.

public void LockRotation()
{
    ScreenOrientation orientation;

    var surfaceOrientation = Activity.WindowManager.DefaultDisplay.Rotation;

    switch (surfaceOrientation) {
        case SurfaceOrientation.Rotation0:
            orientation = ScreenOrientation.Portrait;
            break;
        case SurfaceOrientation.Rotation90:
            orientation = ScreenOrientation.Landscape;
            break;
        case SurfaceOrientation.Rotation180:
            orientation = ScreenOrientation.ReversePortrait;
            break;
        default:
            orientation = ScreenOrientation.ReverseLandscape;
            break;
    }

    Activity.RequestedOrientation = orientation;
}

public void UnlockRotation()
{
    Activity.RequestedOrientation = ScreenOrientation.Unspecified;
}

这个还没有经过测试,因为之前采用了不同的方法,但可能会有用。


这个答案和pstoppani的一样,在平板电脑上会失败。 - Tim Autin

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