【发布时间】:2011-04-20 07:04:24
【问题描述】:
我刚刚实现了一个方向更改功能 - 例如当布局从纵向变为横向(反之亦然)时。如何检测方向更改事件何时完成。
OrientationEventListener 不起作用。如何获取有关布局方向更改事件的通知?
【问题讨论】:
-
在我的例子中,onCreate() 在方向改变时被调用。
标签: android
我刚刚实现了一个方向更改功能 - 例如当布局从纵向变为横向(反之亦然)时。如何检测方向更改事件何时完成。
OrientationEventListener 不起作用。如何获取有关布局方向更改事件的通知?
【问题讨论】:
标签: android
使用 Activity 的 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();
}
}
您还必须在清单文件中编辑适当的 元素以包含 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"。 p>
希望这会对你有所帮助... :)
【讨论】:
要在 layout-land 文件夹中加载布局意味着您有两个单独的布局,那么您必须在 onConfigurationChanged 方法中创建 setContentView。
@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(Configuration newConfig) 方法(如this answer),但我没有自己处理它,而是设置了一个布尔标志,然后调用recreate() 方法,以便Android以正常方式重新创建活动。
recreate() 方法的一个问题是它会导致屏幕短暂闪烁黑色。出于这个原因,我使用了另一种方法:(1)将屏幕宽度保存在onCreate(...) 中,(2)在活动终止时以任何生命周期方法将保存的屏幕宽度与当前屏幕宽度进行比较(例如@987654330 @)。
只是想向您展示一种在 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");
}
如果你添加这个,你所有的 crated 类都将被保存到 MainActivity。
但最好的方法是将其添加到您的 AndroidManifest 中:
<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>
【讨论】:
onConfigurationChanged() 可以使您的instanceState 在方向更改时不会被破坏,因此您不必保存它。您可能希望将其保存为活动生命周期中的其他事件,但我不知道。
使用这个方法
@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>
【讨论】:
如果这对一些较新的开发人员有用,因为上面没有指定。非常明确:
如果使用 onConfigurationChanged,你需要做两件事:
Activity 类中的 onConfigurationChanged 方法
在您的清单中指定哪些配置更改将由您的onConfigurationChanged 方法处理
上述答案中的清单 sn-p 虽然对于清单所属的特定应用程序无疑是正确的,但 不是 正是您需要在 清单中添加的内容 触发 Activity 类中的 onConfigurationChanged 方法。即以下清单条目可能不适合您的应用。
<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>
在上面的清单条目中,android:configChanges="" 的各种 Android 操作可以在您的 Activity 生命周期中触发 onCreate。
这非常重要 - 清单中未指定的那些是触发您的 onCreate 的那些和 清单中指定的那些是触发您的 onConfigurationChanged 方法的那些 在您的 Activity 类中。
因此,您需要确定自己需要处理哪些配置更改。对于像我这样的 Android Encyclopedically Challenged,我使用了 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"/>
所以我的建议,虽然我确信有人可以在这方面戳破:
使用 TOAST 或 LOG 在 Activity 类中添加您的 onConfigurationChanged 方法,以便您查看它何时工作。
将所有可能的配置选项添加到您的清单中。
通过测试您的应用来确认您的 onConfigurationChanged 方法是否有效。
每次从清单文件中删除每个配置选项,然后测试您的应用。
在尽可能多的设备上进行测试。
不要将我上面的 sn-p 复制/粘贴到清单文件中。 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);
}
}
}
【讨论】:
覆盖活动的方法onConfigurationChanged
【讨论】:
创建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"
暗示我们明确声明要注入的布局。
如果我们想通过 layout-land 和 layout 文件夹保持自动注入。您所要做的就是将其添加到 onCreate:
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
getSupportActionBar().hide();
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
getSupportActionBar().show();
}
在这里,我们根据手机的方向显示或不显示操作栏
【讨论】:
如果其他人像我一样在这方面花费太长时间 - 它在模拟器上不起作用。必须是真实设备。
【讨论】:
如果接受的答案对您不起作用,请确保您没有在清单文件中定义:
android:screenOrientation="portrait"
这是我的情况。
【讨论】:
对于 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")
}
}
【讨论】: