如何检测Android中布局的方向变化?


110

我刚刚实现了方向更改功能-例如,当布局从纵向更改为横向时(反之亦然)。如何检测方向更改事件何时结束。

OrientationEventListener没有工作。如何获得有关布局方向更改事件的通知?


在我的情况下,当方向更改时会调用onCreate()。
Josiel Novaes '16

Answers:


293

使用Activity 的onConfigurationChanged方法。请参阅以下代码:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

您还必须编辑适当的 清单文件中的元素,以包含android:configChanges 只需查看以下代码:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

注意:在Android 3.2(API级别13)或更高版本中,当设备在纵向和横向之间切换时,“屏幕尺寸”也会更改。因此,如果要防止在开发API级别13或更高版本时由于方向改变而导致运行时重启,则必须为API级别13或更高版本声明android:configChanges =“ orientation | screenSize”

希望这个能对您有所帮助... :)


3
这很好,但是它确实将布局xml加载到使用纵向xml布局文件的layout-land文件夹中。
程序员

22
Aztec Coder,当您包含“ android:configChanges =“ orientation”时,您将声明将处理方向更改,这意味着在切换到横向时不会重新创建您的活动,而是调用onConfigurationChanged。 ,您可以使用变量记住活动的方向,并且每次使用onPause时(例如)检查方向是否仍然相同
Elena 2012年

14
如果您是API等级13(3.2)或更高版本开发,应指定机器人:configChanges =“方向|屏幕尺寸”,否则onConfigurationChanged不会被调用:developer.android.com/guide/topics/resources/...
阿恩

1
嗨,我正在用API 10(Android 2.3.3)构建我的应用程序。当我使用android:configChanges =“ orientation | keyboardHidden”时,它可以完美地识别方向。但是运行Android 4.1.2的Nexus S无法检测到方向变化,我该怎么办?
Karthik Andhamil

2
在清单文件中使用android:configChanges =“ orientation | screenSize”代替android:configChanges =“ orientation | keyboardHidden”并检查...!
Dinesh Sharma

15

为了将布局加载到layout -land文件夹中,意味着您有两个单独的布局,然后必须使用setContentViewin onConfigurationChanged方法。

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        setContentView(R.layout.yourxmlinlayout-land);
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        setContentView(R.layout.yourxmlinlayoutfolder);
    }
}

如果只有一个布局,则无需在此方法中设置setContentView。只是

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

19
而不是覆盖,只需使用layout / main.xml和layout-land / main.xml。
贾里德·伯罗斯


我想检测到我的活动由于屏幕旋转而终止。我实现了该onConfigurationChanged(Configuration newConfig)方法(如本答案所示),但是我没有自己处理它,而是设置了一个Boolean标志,然后调用该recreate()方法,以便Android以正常方式重新创建活动。
晕眩

recreate()方法的一个问题是它导致屏幕短暂闪烁黑色。因此,我使用了另一种方法:(1)将屏幕宽度保存在中onCreate(...),(2)在活动终止时(例如onSaveInstanceState(...)),以任何生命周期方法将保存的屏幕宽度与当前屏幕宽度进行比较。
昏昏欲睡的

13

只是想向您展示一种在onConfigurationChanged之后保存所有Bundle的方法:

在课程结束后创建新的捆绑包:

public class MainActivity extends Activity {
    Bundle newBundy = new Bundle();

接下来,在“ protected void onCreate”之后添加以下内容:

@Override
public void onConfigurationChanged(Configuration newConfig) {
     super.onConfigurationChanged(newConfig);
     if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            onSaveInstanceState(newBundy);
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            onSaveInstanceState(newBundy);
        }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBundle("newBundy", newBundy);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    savedInstanceState.getBundle("newBundy");
}

如果添加此选项,则所有创建的类都将保存到MainActivity中。

但是最好的方法是在AndroidManifest中添加以下代码:

<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>

7
这是误导。实现后onConfigurationChanged(),您的instanceState不会在方向更改时被销毁,因此您不必保存它。您可能希望将其保存为活动生命周期中的其他事件,但我不知道。
2015年

5

使用这种方法

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
    {
        Toast.makeText(getActivity(),"PORTRAIT",Toast.LENGTH_LONG).show();
       //add your code what you want to do when screen on PORTRAIT MODE
    }
    else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
    {
        Toast.makeText(getActivity(),"LANDSCAPE",Toast.LENGTH_LONG).show();
        //add your code what you want to do when screen on LANDSCAPE MODE
   }
}

并且不要忘记在Androidmainfest.xml中添加它

android:configChanges="orientation|screenSize"

像这样

<activity android:name=".MainActivity"
          android:theme="@style/Theme.AppCompat.NoActionBar"
          android:configChanges="orientation|screenSize">

    </activity>


1

如上所述,事实上,我只想提出另一个与您有关的替代方法:

android:configChanges="orientation|keyboardHidden" 

表示我们显式声明要注入的布局。

万一我们希望保留自动注入功能,这要归功于layout-land和layout文件夹。您所要做的就是将其添加到onCreate中:

    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        getSupportActionBar().hide();

    } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        getSupportActionBar().show();
    }

在这里,我们根据手机的方向显示或不显示操作栏


0

创建一个OrientationEventListener类的实例并启用它。

OrientationEventListener mOrientationEventListener = new OrientationEventListener(YourActivity.this) {
    @Override
    public void onOrientationChanged(int orientation) {
        Log.d(TAG,"orientation = " + orientation);
    }
};

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

2
请不要破坏您的答案。如果要删除它,可以在答案的左下方找到“删除”按钮。
CalvT

0

如果接受的答案对您不起作用,请确保未在清单文件中定义:

android:screenOrientation="portrait"

这是我的情况。


0

如果这对某些较新的开发人员有用,因为上面没有指定。只是非常明确:

如果使用onConfigurationChanged,则需要两件事:

  1. onConfigurationChanged您的Activity类中的方法

  2. 在清单中指定将由您的onConfigurationChanged方法处理的配置更改

清单片段在上面的答案,而无疑是正确的特定应用程序,明显属于,是不是正是你需要在添加什么您的清单来触发你的活动课的onConfigurationChanged方法。即,以下清单条目可能不适用于您的应用。

<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>

在上述清单条目中,有各种Android操作android:configChanges=""可以触发您的Activity生命周期中的onCreate。

这非常重要- 清单中未指定的那些触发您的onCreate清单中指定的那些触发您onConfigurationChanged的Activity类中的方法

因此,您需要确定需要处理的配置更改。对于像我这样的Android百科全书挑战者,我使用了Android Studio中的快速提示弹出窗口,并添加了几乎所有可能的配置选项。列出所有这些基本上表示我将处理所有事情,并且由于配置而永远不会调用onCreate。

<activity name= ".MainActivity" android:configChanges="screenLayout|touchscreen|mnc|mcc|density|uiMode|fontScale|orientation|keyboard|layoutDirection|locale|navigation|smallestScreenSize|keyboardHidden|colorMode|screenSize"/>

现在显然我不想处理所有事情,因此我开始一次消除了上述选项。每次删除后重新构建和测试我的应用。

另一个要点:如果仅自动处理一个触发您的onCreate的配置选项(上面的清单中没有列出该选项),那么它将似乎onConfigurationChanged无法正常工作。您必须将所有相关的内容放入清单中。

我得到了3个最初触发onCreate的结果,然后我在S10 +上进行了测试,但仍得到onCreate,因此我不得不再次进行消除练习,并且我还需要使用|screenSize。因此,请在多种平台上进行测试。

<activity name= ".MainActivity" android:configChanges="screenLayout|uiMode|orientation|screenSize"/>

因此,我的建议是,尽管我确定有人可以在此戳破漏洞:

  1. onConfigurationChanged使用TOAST或LOG在活动类中添加方法,以便查看其工作时间。

  2. 将所有可能的配置选项添加到清单中。

  3. onConfigurationChanged通过测试您的应用程序来确认您的方法是否有效。

  4. 一次从清单文件中删除每个配置选项,然后逐个测试您的应用程序。

  5. 在尽可能多的各种设备上进行测试。

  6. 不要将上面的代码段复制/粘贴到清单文件中。Android更新会更改列表,因此请使用弹出的Android Studio提示来确保全部获取。

我希望这可以节省一些时间。

我的onConfigurationChanged方法仅供参考。onConfigurationChanged在生命周期被称为新的方向是可用的,但之前的UI已创建。因此,我首先if检查方向是否正确,然后第二次嵌套if以查看UI ImageView的可见性也正确地工作。

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        // Checks the orientation of the screen
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            pokerCardLarge = findViewById(R.id.pokerCardLgImageView);

            if(pokerCardLarge.getVisibility() == pokerCardLarge.VISIBLE){
                Bitmap image = ((BitmapDrawable)pokerCardLarge.getDrawable()).getBitmap();
                pokerCardLarge.setVisibility(pokerCardLarge.VISIBLE);
                pokerCardLarge.setImageBitmap(image);
            }

        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            pokerCardLarge = findViewById(R.id.pokerCardLgImageView);

            if(pokerCardLarge.getVisibility() == pokerCardLarge.VISIBLE){
                Bitmap image = ((BitmapDrawable)pokerCardLarge.getDrawable()).getBitmap();
                pokerCardLarge.setVisibility(pokerCardLarge.VISIBLE);
                pokerCardLarge.setImageBitmap(image);
            }

        }
    }

0

以最简单的形式实现Kotilin的实现-仅在屏幕从纵向<->横向更改时触发,如果需要设备进行翻转检测(180度),则需要输入重力传感器值

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

val rotation = windowManager.defaultDisplay.rotation

    when (rotation) {            
        0 -> Log.d(TAG,"at zero degree")
        1 -> Log.d(TAG,"at 270 degree")
        2 -> Log.d(TAG,"at 180 degree")
        3 -> Log.d(TAG,"at 90 degree")


    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.