众所周知,Android 如果用Activity做横屏处理是相当简单的,就一个配置解决,剩下的就是修改横屏相应的布局。
但是。Fragment要做的跟Activity那么完美就没那么简单了。
接下来就是我解决这个坑花了3天时间的总结(大致效果跟高德地图的导航界面旋转一样的效果):
1.使用SensorManager重力感应,在初始化需要横屏的Fragment的时候,自己写根据感应角度旋转屏幕。
2.在onConfigurationChanged事件布置两个竖屏横屏的布局。
3.在打开别的Fragment或者返回上一个Fragment前,分别关闭重力感应,并且使它竖屏。
为什么要自己弄的那么麻烦,没办法,Android对于横竖屏的支持,只有Activity,无奈我优化这个App用的布局是单Activity和全部Fragment的方式。所以算是自己挖的深坑吧,但是总算完美解决了,代码冗余还是要解决下。
网上搜索相关内容也没有,应该这么做的部分人很少很少,所以我感觉应该也没什么人需要这部分代码……
demo链接,有帮助到您的欢迎star或者意思意思个咖啡小资 :)
https://github.com/zhongjhATC/RotateFragment
1.初始相关变量
// region 重力感应
protected boolean isLandscape = false; // 默认是竖屏
protected SensorManager sm;
protected OrientationSensorListener listener;
protected Sensor sensor;
protected ContentObserver mSettingsContentObserver; // 监控方向锁定
// endregion
2.初始化相关
// 初始化重力感应器
sm = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
sensor = sm.getDefaultSensor(Sensor.TYPE_GRAVITY);
listener = new OrientationSensorListener(mHandler, _mActivity);
// 设置事件
mSettingsContentObserver = new ContentObserver(new Handler()) {
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// 启动重力感应
if (Settings.System.getInt(_mActivity.getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, 0) == 1) {
// 1为自动旋转模式,0为锁定竖屏模式
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
} else {
sm.unregisterListener(listener);
}
}
};
3.这段代码是控制手机横竖屏的
// region 重力感应
/**
* 接收重力感应监听的结果,来改变屏幕朝向
*/
private Handler mHandler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
if (msg.what == 888) {
int orientation = msg.arg1;
/**
* 根据手机屏幕的朝向角度,来设置内容的横竖屏,并且记录状态
*/
if (orientation > 45 && orientation < 135) {
_mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
isLandscape = true;
} else if (orientation > 135 && orientation < 225) {
_mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
isLandscape = false;
} else if (orientation > 225 && orientation < 315) {
_mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
isLandscape = true;
} else if ((orientation > 315 && orientation < 360) || (orientation > 0 && orientation < 45)) {
_mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
isLandscape = false;
}
}
}
};
/**
* 重力感应监听者
*/
public class OrientationSensorListener implements SensorEventListener {
private boolean isClickFullScreen; // 记录全屏按钮的状态,默认false
private boolean isEffetSysSetting = false; // 手机系统的重力感应设置是否生效,默认无效,想要生效改成true就好了
private boolean isOpenSensor = true; // 是否打开传输,默认打开
private boolean isLandscape = false; // 默认是竖屏
private boolean isChangeOrientation = true; // 记录点击全屏后屏幕朝向是否改变,默认会自动切换
private static final int _DATA_X = 0;
private static final int _DATA_Y = 1;
private static final int _DATA_Z = 2;
public static final int ORIENTATION_UNKNOWN = -1;
private Handler rotateHandler;
private Activity activity;
public OrientationSensorListener(Handler handler, Activity activity) {
rotateHandler = handler;
this.activity = activity;
}
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
int orientation = ORIENTATION_UNKNOWN;
float X = -values[_DATA_X];
float Y = -values[_DATA_Y];
float Z = -values[_DATA_Z];
float magnitude = X * X + Y * Y;
// Don't trust the angle if the magnitude is small compared to the y
// value
if (magnitude * 4 >= Z * Z) {
// 屏幕旋转时
float OneEightyOverPi = 57.29577957855f;
float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;
orientation = 90 - Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
}
while (orientation < 0) {
orientation += 360;
}
}
/**
* 获取手机系统的重力感应开关设置,这段代码看需求,不要就删除
* screenchange = 1 表示开启,screenchange = 0 表示禁用
* 要是禁用了就直接返回
*/
if (isEffetSysSetting) {
try {
int isRotate = Settings.System.getInt(activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION);
// 如果用户禁用掉了重力感应就直接return
if (isRotate == 0) return;
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
}
// 只有点了按钮时才需要根据当前的状态来更新状态
if (isClickFullScreen) {
if (isLandscape && screenIsPortrait(orientation)) { // 之前是横屏,并且当前是竖屏的状态
updateState(false, false, true, true);
} else if (!isLandscape && screenIsLandscape(orientation)) { // 之前是竖屏,并且当前是横屏的状态
updateState(true, false, true, true);
} else if (isLandscape && screenIsLandscape(orientation)) { // 之前是横屏,现在还是横屏的状态
isChangeOrientation = false;
} else if (!isLandscape && screenIsPortrait(orientation)) { // 之前是竖屏,现在还是竖屏的状态
isChangeOrientation = false;
}
}
// 判断是否要进行中断信息传递
if (!isOpenSensor) {
return;
}
if (rotateHandler != null) {
rotateHandler.obtainMessage(888, orientation, 0).sendToTarget();
}
}
/**
* 当前屏幕朝向是否竖屏
*
* @param orientation
* @return
*/
private boolean screenIsPortrait(int orientation) {
return (((orientation > 315 && orientation <= 360) || (orientation >= 0 && orientation <= 45))
|| (orientation > 135 && orientation <= 225));
}
/**
* 当前屏幕朝向是否横屏
*
* @param orientation
* @return
*/
private boolean screenIsLandscape(int orientation) {
return ((orientation > 45 && orientation <= 135) || (orientation > 225 && orientation <= 315));
}
/**
* 更新状态
*
* @param isLandscape 横屏
* @param isClickFullScreen 全屏点击
* @param isOpenSensor 打开传输
* @param isChangeOrientation 朝向改变
*/
private void updateState(boolean isLandscape, boolean isClickFullScreen, boolean isOpenSensor, boolean isChangeOrientation) {
this.isLandscape = isLandscape;
this.isClickFullScreen = isClickFullScreen;
this.isOpenSensor = isOpenSensor;
this.isChangeOrientation = isChangeOrientation;
}
}
// endregion
4.在fragment的显示,返回,销毁等等生命周期都要严格控制重力感应
@Override
public void onEnterAnimationEnd(Bundle savedInstanceState) {
super.onEnterAnimationEnd(savedInstanceState);
// 启动重力感应
if (Settings.System.getInt(_mActivity.getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, 0) == 1) {
// 1为自动旋转模式,0为锁定竖屏模式
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
}
}
@Override
public void onSupportVisible() {
super.onSupportVisible();
// 重新开启重力感应
if (Settings.System.getInt(_mActivity.getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, 0) == 1) {
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
}
}
@Override
public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
// 重新开启重力感应
if (Settings.System.getInt(_mActivity.getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, 0) == 1) {
sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
}
super.onFragmentResult(requestCode, resultCode, data);
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
// 关闭重力感应
sm.unregisterListener(listener);
// 关闭监控手机方向锁定
_mActivity.getContentResolver().unregisterContentObserver(mSettingsContentObserver);
}