目前在开发一个平板App,当然了,平板app是横屏的,需要实现跟随系统切换正向横屏和反向横屏。
先看下设备方向和角度示意:
需要实现的功能:
- 系统关闭屏幕旋转且当前为正向竖屏或反向竖屏时,打开app是正向横屏
- 系统关闭屏幕旋转且当前为正向横屏时,打开app是正向横屏
- 系统关闭屏幕旋转且当前为反向横屏时,打开app是反向横屏
- 系统打开屏幕旋转且当前为正向竖屏或反向竖屏时,打开app是正向横屏
- 系统打开屏幕旋转且当前为正向横屏时,打开app是正向横屏
- 系统打开屏幕旋转且当前为反向横屏时,打开app是反向横屏
- 在app运行过程中,如果系统关闭了屏幕旋转,app跟随关闭屏幕旋转,反之则开启
思路和遇到的问题:
一开始想的是xml中不配置Activity的android:screenOrientation
,页面初始化的时候在代码中动态设置requestedOrientation
为横屏,但是这会导致一个问题,就是打开页面会先是竖屏状态,然后切换成横屏,一是体验差,二是可能会导致需要动态计算宽高的view变形。
后来在xml配置screenOrientation为landscape,然后代码中再动态设置正确的方向,这样就能避免上一个问题,但是又出现一个新的问题,就是在反向横屏状态下,打开app会先强制转为正向横屏,再旋转为反向横屏。
最后,将所有Activity在xml中默认配置为sensorLandscape,这样,不管当前系统屏幕处于什么方向,打开app后就能显示正确的方向(正向横屏或者反向横屏)。
代码:
class OrientationUtils {
companion object {
val util by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
OrientationUtils()
}
}
private var mOrientationEventListener: OrientationEventListener? = null
fun initOrientation(activity: Activity) {
//当前屏幕方向
var rotation = activity.windowManager.defaultDisplay.rotation
//当前系统旋转状态 1开启自动旋转 0禁用系统旋转
var rotationStatus = Settings.System.getInt(
activity.contentResolver,
Settings.System.ACCELEROMETER_ROTATION,
0
)
/*---初始屏幕方向设置---*/
//所有Activity必须默认是sensorc(根据重力感应传感器去切换正反横屏)
// 当系统自动旋转禁用时,判断当前屏幕方向
//如果是Surface.ROTATION_90,表示是正向横屏,设置为SCREEN_ORIENTATION_LANDSCAPE
//如果是Surface.ROTATION_270,表示是反向横屏,设置为SCREEN_ORIENTATION_REVERSE_LANDSCAPE
if (rotationStatus == 0) {
when (rotation) {
Surface.ROTATION_90 -> activity.requestedOrientation =
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
Surface.ROTATION_270 -> activity.requestedOrientation =
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
}
}
/*---监听重力传感器设置屏幕方向---*/
mOrientationEventListener = object : OrientationEventListener(activity) {
override fun onOrientationChanged(orientation: Int) {
rotation = activity.windowManager.defaultDisplay.rotation
rotationStatus = Settings.System.getInt(
activity.contentResolver,
Settings.System.ACCELEROMETER_ROTATION,
0
)
//系统自动旋转禁用时,使用之前的设置,不再判断重力感应
if (rotationStatus == 0) {
return
}
//设备躺平,使用之前的设置,不再判断重力感应
if (orientation == ORIENTATION_UNKNOWN) {
return
}
//将所有旋转角度归结为四个方向
val newOrientation: Int = if (orientation > 350 || orientation < 10) {
0
} else if (orientation in 81..99) {
90
} else if (orientation in 171..189) {
180
} else if (orientation in 261..279) {
270
} else {
return
}
//90度:设置为正向横屏 180度:设置为反=反向横屏,0和180为正反纵向,不改变屏幕方向
when (newOrientation) {
90 -> {
activity.requestedOrientation =
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
}
270 -> {
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
}
}
}
mOrientationEventListener?.enable()
}
}