横竖屏切换方法:
1.自动切换:
1.通过在androidManifest.xml的activity节点添加screenOrientation属性:
//screenOrientation属性说明:
unspecified:默认值,由系统决定;
landscape:设置横屏显示(不管当前手机是什么方向,activity都是横屏且方向不会变);
portrait:设置竖屏显示(activity一直是竖屏的);
behind:与前一个activity方向相同;
sensor:activity方向根据物理传感器方向转动,旋转方向为0度,90度,180度,270度(即手机的四侧,手机顶部在上时activity上部分在手机顶部,手机底部在上时activity上部分在手机底部,手机左侧在上时activity顶部在左侧,手机右侧在上时activity上部分在右侧);
sensorLandscape:activity横屏且根据传感器设置方向(此时方向只有90度,270度,即左右两侧);
sensorPortrait:activity竖屏且根据传感器设置方向(旋转0度或者180度);
nosensor:旋转设备时候,界面不会跟着旋转;
user:用户当前设置的方向;
此时如果想要activity根据传感器方向变方向时设置screenOrientation为sensor或者sensorLandscape或者sensorPortrait即可。
2.通过动态注册传感器动态设置:
在activity中或者fragment中或者相应的逻辑中添加:
private OrientationEventListener mOrientationListener = new OrientationEventListener(getActivity(), SensorManager.SENSOR_DELAY_NORMAL) {
@Override
public void onOrientationChanged(int rotation) {
// 设置竖屏
if (getActivity() == null || getActivity().isFinishing()) {
return;
}
requestedOrientation(rotation);//根据传感器设置屏幕方向
}
};
//设置listener是否启动,在相应时机调用,只有在enable时才能监听传感器方向
private void enableSensor(){
if (mOrientationListener.canDetectOrientation()) {
mOrientationListener.enable();
} else {
mOrientationListener.disable();
}
}
/**
* 描述:改变屏幕方向
*/
private void requestedOrientation(int rotation) {//此时的rotation为传感器旋转的角度
if (rotation < 10 || rotation > 350) {// 手机顶部向上
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (rotation < 100 && rotation > 80) {// 手机右边向上
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
} else if (rotation < 190 && rotation > 170) {// 手机低边向上
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
} else if (rotation < 280 && rotation > 260) {// 手机左边向上
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
注:要在相应的时机注销掉listener,否则会出现内存泄漏:
if (mOrientationListener != null) {
mOrientationListener.disable();
mOrientationListener = null;
}
想动态设置activity方向时调用activity.setRequestedOrientation方法即可,其中可设置的值可在ActivityInfo类中查看(属性中有的都可以动态设置,其中类中还有其他的一些有趣的东西有兴趣的话可以看下)。
相关的一些问题:
1.activity生命周期问题
横竖屏切换时会先销毁相应activity,后在创建横屏或竖屏的activity,因此生命周期为onPause-> onStop-> onDestory-> onCreate->onStart->onResume;
此时如果如果有layout-land下的activity布局时横竖屏切换时会使用不同的布局xml文件。
如果不想让activity重新创建时在manifest的activity节点处添加属性:
android:configChanges="orientation|screenSize"
2.自动切换时布局问题
横竖屏切换时如果重新创建了activity会重新加载相应的布局文件(layout下的或者layout-land下的),但如果设置了configChanges="orientation|screenSize"由于不会重新创建activity所以布局只会使用竖屏的布局文件。
屏幕方向变化之后会回调activity或者fragment的onConfigurationChanged方法。
此时如果想要适配横竖屏:
1.可在onConfigurationChanged中重新设置下contentview:
//1.布局分别在layout-land和layout-port目录中的同名main.xml时
@Override
public void onConfigurationChanged (Configuration newConfig){
super.onConfigurationChanged(newConfig);
setContentView(R.layout.main);
//注意,这里删除了init(),否则又初始化了,状态就丢失
findViews();
setListensers();
}
//2.布局为不按照layout-land和layout-port目录,而自定义名字时
@Override
public void onConfigurationChanged (Configuration newConfig){
super.onConfigurationChanged(newConfig);
int mCurrentOrientation = getResources().getConfiguration().orientation;
if ( mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT ) {
// If current screen is portrait
setContentView(R.layout.mainP);
//注意,这里删除了init(),否则又初始化了,状态就丢失
findViews();
setListensers();
} else if ( mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE ) {
//If current screen is landscape
setContentView(R.layout.mainL);
//注意,这里删除了init(),否则又初始化了,状态就丢失
findViews();
setListensers();
}
}
2.或者直接设置view的宽高大小或者比例:
比如直播时竖屏时小屏幕设置自定义的比例,竖屏时设置宽高比的比例即可填满屏幕。
注:如果使用的screenOrientation为sensorLandscape或者sensorPortrait时,在手机方向切换后并不会触发onConfigurationChanged回调,如果想监听手机屏幕方向改变可添加OrientationEventListener。
3.使用今日头条适配时横屏列表项尺寸异常问题
由于在项目中使用了今日头条的适配方案(使用可看:https://blog.csdn.net/weixin_42493749/article/details/82982880 ),但是在横竖屏切换后列表项在滚动时发现尺寸异常了,解决方案为在adapter的bindview或者getview时调用:
AutoSize.autoConvertDensity((Activity) getContext(), 400f, true);
具体参数的解释可进入方法中查看就不多说了,能解决的原因也可在方法中看到:在view绘制前Density修改了,绘制完成后Density又重置了回去导致view测量绘制所使用的Density值不同就导致了view的大小不同;同时项目中有一个逻辑是在网络请求完成后填充recyclerview时view特别小也是在请求完成后添加了这行代码view尺寸正常了。