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

我刚刚实现了一个方向改变功能-例如,当布局从肖像到景观(或反之亦然)变化。如何检测方向更改事件何时结束。

OrientationEventListener没有工作。我怎样才能得到关于布局方向更改事件的通知?

192946 次浏览

Override activity's method OnConfigurationChanged

使用活动的 OnConfigurationChanged方法。 请参阅以下代码:

@Override
public void onConfigurationChanged(@NotNull 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();
}
}

您还必须在清单文件中编辑适当的 元素,以包含 < strong > android: configChanges 请看下面的代码:

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

注意: 对于 Android 3.2(API 级别13)或更高版本,当设备在纵向和横向之间切换时,“屏幕大小”也会发生变化。因此,如果要防止在开发 API 级别13或更高的应用程序时由于方向更改而导致运行时重新启动,则必须声明 Android: configChanges = API 级别13或更高的“方向 | 屏幕大小”

希望这个对你有帮助... :)

对于加载的布局在 布局-土地文件夹意味着你有两个单独的布局,然后你必须使 setContentViewonConfigurationChanged方法。

@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);
}

只是想告诉你一个在 onConfigurationChanged 之后保存所有捆绑包的方法:

在课后创建新的捆绑包:

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 中的类都将被保存。

但是最好的方法是在你的 Android 清单中添加这个:

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

使用这种方法

@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"

like this

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


</activity>

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

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


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

我只是想提出另一个选择,这将关系到你们中的一些人,事实上,如上所述:

android:configChanges="orientation|keyboardHidden"

意味着我们显式地声明要注入的布局。

如果我们想保持自动注入感谢布局-土地和布局文件夹。您所要做的就是将它添加到 onCreate:

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


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

Here, we display or not the actionbar depending on the orientation of the phone

如果接受的答案不适合您,请确保您没有在清单文件中定义:

android:screenOrientation="portrait"

这是我的案子。

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

如果使用 OnConfigurationChanged,您需要两样东西:

  1. 活动类中的 onConfigurationChanged方法

  2. 在清单中指定哪个配置更改了 将由您的 onConfigurationChanged方法

上面答案中的清单片段,毫无疑问,对于清单所属的特定应用程序来说是正确的,这正是您需要在 你的旅客名单中添加的 NOT,以触发 Activity Class 中的 onConfigurationChanged 方法。即下面的清单条目 可能不适合你的应用程序。

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

在上面的清单条目中,有各种针对 android:configChanges=""的 Android 操作,它们可以在您的活动生命周期中触发 onCreate。

这是非常重要的-清单中没有指定的那些是触发 onCreate 的那些在清单中指定的是触发 onConfigurationChanged方法的方法在您的活动类。

因此,您需要确定需要自己处理哪些配置更改。对于像我一样的 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. 在活动类中添加带有 TOAST 或 LOG 的 onConfigurationChanged方法,这样您就可以看到它何时工作。

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

  3. 通过测试你的应用程序,确认你的 onConfigurationChanged方法正在工作。

  4. 每次从清单文件中删除一个配置选项,并在每个选项之后测试应用程序。

  5. Test on as large a variety of devices as possible.

  6. Do not copy/paste my snippet above to your manifest file. Android updates change the list, so use the pop-out Android Studio hints to make sure you get them all.

我希望这能节省一些时间。

我的 onConfigurationChanged方法只是为了下面的信息。onConfigurationChanged在生命周期中被调用 after,新的方向是可用的,但是 之前的 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);
}


}
}

对于 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")




}
}

以防其他人像我一样在这上面花太多时间——它在模拟器上不起作用。必须是真正的装置。