我刚刚实现了一个方向变化功能 - 比如当布局从竖屏变为横屏(或反之亦然)时。如何检测方向变化事件何时完成。
OrientationEventListener
无法正常工作。如何获取有关布局方向更改事件的通知?
我刚刚实现了一个方向变化功能 - 比如当布局从竖屏变为横屏(或反之亦然)时。如何检测方向变化事件何时完成。
OrientationEventListener
无法正常工作。如何获取有关布局方向更改事件的通知?
使用Activity的onConfigurationChanged
方法,如Android文档中“处理运行时变化”指南所述:
@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(); } }
You also have to edit the appropriate element in your manifest file to include the android:configChanges:
<activity android:name=".MyActivity" android:configChanges="orientation|keyboardHidden" android:label="@string/app_name">
NOTE: with Android 3.2 (API level 13) or higher, the "screen size" also changes when the device switches between portrait and landscape orientation. Thus, if you want to prevent runtime restarts due to orientation change when developing for API level 13 or higher, you must declare android:configChanges="orientation|screenSize" for API level 13 or higher.
如果在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);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
onConfigurationChanged(Configuration newConfig)
方法(如此答案中所述),但我没有自己处理它,而是设置了一个布尔标志,然后调用了recreate()
方法,以便Android以正常方式重新创建活动。 - dazedrecreate()
方法的一个问题是它会导致屏幕短暂闪黑。因此,我采用了另一种方法:(1)在 onCreate(...)
中保存屏幕宽度,(2)在任何生命周期方法中比较保存的屏幕宽度和当前屏幕宽度,当活动被终止时(例如 onSaveInstanceState(...)
)。 - dazed我想向您展示一种在onConfigurationChanged后保存所有Bundle的方法:
在您的类之后创建一个新的Bundle:
public class MainActivity extends Activity {
Bundle newBundy = new Bundle();
接下来,在 "protected void onCreate" 后面添加这些内容:
接下来,在 "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中创建的所有类中,它们都将被保存。<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>
onConfigurationChanged()
可以使您的instanceState
在方向更改时不被销毁,因此您不需要保存它。您可能希望为活动生命周期中的其他事件保存它,但我不确定。 - izzy使用这种方法
@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
}
}
android:configChanges="orientation|screenSize"
like this
<activity android:name=".MainActivity"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:configChanges="orientation|screenSize">
</activity>
如果对于某些较新的开发者有用的话,因为上面没有指定,我想说得很明确:
如果使用onConfigurationChanged,您需要两个东西:
在Activity类中编写一个onConfigurationChanged
方法
在您的清单文件中指定哪些配置更改将由您的onConfigurationChanged
方法处理
上面的答案中的清单片段,虽然毫无疑问是适用于该清单所属的特定应用程序,但却不是您需要在您的清单文件中添加以触发Activity类中的onConfigurationChanged方法的确切内容。也就是说,以下清单条目可能不适合您的应用程序。
<activity name= ".MainActivity" android:configChanges="orientation|screenSize"/>
android:configChanges=""
,可以触发您的 Activity 生命周期中的 onCreate。onConfigurationChanged
方法的操作。<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"/>
所以,虽然我相信有人能够挑出这个问题:
在您的活动类中添加onConfigurationChanged
方法,并使用TOAST或LOG进行验证,以便您可以看到它何时工作。
将所有可能的配置选项添加到您的清单中。
通过测试您的应用程序来确认onConfigurationChanged
方法是否正常工作。
逐个从您的清单文件中删除每个配置选项,在每次测试后测试您的应用程序。
尽可能在各种设备上进行测试。
不要将我上面的片段复制/粘贴到您的清单文件中。 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);
}
}
}
Override activity's method onConfigurationChanged
OrientationEventListener
类的实例并启用它。OrientationEventListener mOrientationEventListener = new OrientationEventListener(YourActivity.this) {
@Override
public void onOrientationChanged(int orientation) {
Log.d(TAG,"orientation = " + orientation);
}
};
if (mOrientationEventListener.canDetectOrientation())
mOrientationEventListener.enable();
对于Kotlin的最简实现 - 只在屏幕从竖屏 <--> 横屏切换时触发,如果需要检测翻转(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")
}
}
我只是想提出另一种选择,这将涉及到一些人,正如上面所解释的:
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();
}