如何在安卓系统中禁用屏幕旋转?

302

我有一个应用程序,希望仅以竖屏模式使用,因此我在清单XML中定义了android:screenOrientation="portrait"。这对于HTC Magic手机可以正常工作(并防止其他手机的方向更改)。

但使用HTC G1手机的硬件QWERTY键盘(而非虚拟键盘)时存在问题。我的活动保持竖屏模式,但似乎会重新启动并失去所有状态。这在HTC Hero版本中不会发生。

我的应用程序很大,因此不希望在打开键盘时重新启动并丢失所有状态。我该如何防止这种情况发生?


2
尝试在这里查找:https://dev59.com/OXE95IYBdhLWcg3wUMLW#10488012 - Andy Weinstein
可能是重复的问题:如何使应用程序在Android中完全忽略屏幕方向更改?(https://dev59.com/XHM_5IYBdhLWcg3wXx1N) - Peter O.
15个回答

332

2013年4月更新:不要这样做。当我第一次回答这个问题时,它并不是一个好主意,现在也不是。请参考hackbod的答案以了解原因:

避免在Android设备方向改变时使用asynctask重新载入activity

在您的AndroidManifest.xml中添加 android:configChanges="keyboardHidden|orientation"。这告诉系统您将自行处理哪些配置更改 - 在本例中不做任何操作。

<activity android:name="MainActivity"
     android:screenOrientation="portrait"
     android:configChanges="keyboardHidden|orientation">

了解更多细节,请参阅开发人员参考configChanges

然而,您的应用程序可能随时被打断,例如通过电话,因此当应用程序被暂停时,您真的应该添加保存应用程序状态的代码。

更新:从Android 3.2开始,您还需要添加“screenSize”:

<activity
    android:name="MainActivity"
    android:screenOrientation="portrait"
    android:configChanges="keyboardHidden|orientation|screenSize">

来自开发人员指南 手动处理配置更改

注意:从Android 3.2(API级别13)开始,设备在纵向和横向方向切换时,"屏幕尺寸"也会改变。因此,如果您想防止由于方向更改而发生运行时重启(针对minSdkVersion和targetSdkVersion属性声明的API级别为13或更高),则必须除了"orientation"值之外还包括"screenSize"值。也就是说,您必须声明android:configChanges="orientation|screenSize"。但是,如果您的应用程序针对API级别12或更低,则您的activity总是自己处理此配置更改(即使在Android 3.2或更高版本的设备上运行,此配置更改也不会重新启动activity)。


38
为了补充并更加明确,Android可以在任何时候无情地杀死您的应用程序,而不管屏幕方向的改变,因此无论如何都应该使用onPause()和onSaveInstanceState()来保存状态。请注意,这两个方法的目的是为了确保您的应用程序可以恢复到杀死它之前的状态。 - Eric Mill
3.2更新非常有用,而且正是阻止我的东西。我不知道为什么我的onConfigurationChanged处理程序没有触发,这就是原因。谢谢! - sweetlilmre
第三个参数 - screenSize 在2.3.x中找不到,我应该改成screenLayout吗? - deadfish
2
@Lumma 不需要在 Android 3.2 及以上版本中使用 "screenSize"。你的目标 API 级别是多少?我认为只有在目标级别为13或更高时才需要添加它。我会更新答案以澄清这一点。 - Intrications
1
以防对其他人有帮助,我发现您可以使用<...android:configChanges="orientation"...>来覆盖更改,使用<...android:screenOrientation="portrait"...>来定义默认值。 - Sogger
显示剩余2条评论

100

您需要修改AndroidManifest.xml文件,如Intrications(以前是Ashton)所提到的,并确保活动处理onConfigurationChanged事件的方式符合您的要求。以下是应该看起来的样子:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

正如Dmitry Zaitsev所指出的那样,最好将setRequestedOrientation()放在onCreate()中。 - Timmmm
3
如果onConfigurationChanged()会在onCreate()之前被调用,那么在onCreate()中设置内容视图之前设置方向是更好的方法。将配置设置放在应该设置的位置也更加清晰,因此此答案仍然是正确的。 - Samuel

41

我一直认为需要两者兼备

android:screenOrientation="nosensor" android:configChanges="keyboardHidden|orientation"

23

如前所述,在您的Activity中设置android:configChanges(在清单文件中)为keyboardHidden|orientation,然后:

1)覆盖onConfigurationChanged()

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    //here you can handle orientation change
}

2) 将以下代码添加至您的活动的onCreate()方法中

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

添加相同行到 onConfigurationChanged 中会导致应用程序先转换到纵向模式,然后再转换回横向模式(这只会发生一次,但很烦人)。因此使用下面的方法更好:

还可以在清单文件中为您的活动设置 android:screenOrientation="nosensor"但是,使用此方法将无法处理方向更改。


1
如果我想避免在旋转时重新创建活动,但我希望用户可以通过操作系统的设置锁定方向,我该怎么做? - android developer
@androiddeveloper 这是一个单独的问题,已经有答案了:https://dev59.com/_2455IYBdhLWcg3wD_oB#14771495 - Dmitry Zaytsev
您的链接是关于在配置更改时由我自己更改内容,但我希望避免在用户通过操作系统设置锁定方向(某些设备通过快速设置在通知抽屉中可用)的情况下旋转活动(以便它保持完全相同的外观)。 - android developer
@androiddeveloper 啊,我想我明白了。那么请看这个链接:http://developer.android.com/reference/android/R.attr.html#screenOrientation 根据文档,缺省方向应该已经考虑到用户的偏好。如果不是这样的话,那么我怀疑这是一个特定于操作系统的行为。我很乐意听听你的结果 - 现在我也很感兴趣 :) - Dmitry Zaytsev
我知道默认设置会处理用户的偏好,但它也会在旋转屏幕时重新创建活动,这是我不想要的。 - android developer
无论如何,我已经找到了正确的值:android:screenOrientation="user"。我还在这里写了一篇文章,认为我已经尝试了所有的值(可能错过了):http://stackoverflow.com/questions/24000361/how-to-avoid-activity-re-creation-when-being-rotated-while-also-respecting-orie/24004340#24004340 - android developer

21

使用此功能可轻松完成任务。

    android:screenOrientation="portrait"

14
在您的Activity的OnCreate方法中使用以下代码:

在您的Activity的OnCreate方法中使用以下代码:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

现在你的屏幕方向已经设置为竖屏,并且将永远保持不变。


4
每次方向配置更改时,您无法防止重新启动活动。 - AxeEffect
此外,如果您在横向方向从先前的 Activity 进入该 Activity,则此方法将无法正常工作。 - w3bshark

10
在AndroidManifest.xml文件中,对于每个您想要锁定的活动,请添加最后一个screenOrientation行:
android:label="@string/app_name"
android:name=".Login"
android:screenOrientation="portrait" >

或者 android:screenOrientation="landscape"


8

在你的androidmanifest.xml文件中:

   <activity android:name="MainActivity" android:configChanges="keyboardHidden|orientation">

或者

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

7
要通过代码锁定屏幕,您需要使用屏幕的实际旋转角度(0、90、180、270),并且您需要知道它的自然位置,在智能手机中,自然位置将是竖屏,在平板电脑中,自然位置将是横屏。
这是代码(锁定和解锁方法),已在一些设备(智能手机和平板电脑)上进行了测试,并且运行良好。
public static void lockScreenOrientation(Activity activity)
{   
    WindowManager windowManager =  (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);   
    Configuration configuration = activity.getResources().getConfiguration();   
    int rotation = windowManager.getDefaultDisplay().getRotation(); 

    // Search for the natural position of the device    
    if(configuration.orientation == Configuration.ORIENTATION_LANDSCAPE &&  
       (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) ||  
       configuration.orientation == Configuration.ORIENTATION_PORTRAIT &&   
       (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270))   
    {   
        // Natural position is Landscape    
        switch (rotation)   
        {   
            case Surface.ROTATION_0:    
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);    
                break;      
            case Surface.ROTATION_90:   
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); 
            break;      
            case Surface.ROTATION_180: 
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); 
                break;          
            case Surface.ROTATION_270: 
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 
                break;
        }
    }
    else
    {
        // Natural position is Portrait
        switch (rotation) 
        {
            case Surface.ROTATION_0: 
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 
            break;   
            case Surface.ROTATION_90: 
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 
            break;   
            case Surface.ROTATION_180: 
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); 
                break;          
            case Surface.ROTATION_270: 
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); 
                break;
        }
    }
}

public static void unlockScreenOrientation(Activity activity)
{
    activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}

应该传递什么参数作为活动? - WISHY
调用方法锁定/解锁其方向的活动。这是一个公共静态实用方法,可从不同的活动中调用。 - PoOk
1
工作得很好,但是,说真的,Android,为什么我们要为了锁定屏幕方向而做那么多破事!!! - Cocorico
是的。这个代码片段可以像我们在清单文件中做的那样锁定屏幕方向,从而防止 onConfigurationChanged 方法被调用。是否有一种方法可以将 UI 锁定为横向并仍然调用 onConfigurationChanged 方法?就像 Android 中的相机应用程序一样。 - Ajith M A
在SDK 18+上有一个SCREEN_ORIENTATION_LOCKED标志似乎可以工作,但您仍然希望使用上面的代码来支持每个设备。 - DominicM

1
添加
android:configChanges="keyboardHidden|orientation|screenSize" 

将其添加到您的清单中。

在你的<activity>标签内部 - Ege Kuzubasioglu

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