Android横屏app跟随系统切换正反向横屏工具类

1,163 阅读2分钟

目前在开发一个平板App,当然了,平板app是横屏的,需要实现跟随系统切换正向横屏和反向横屏。
先看下设备方向和角度示意:

Android屏幕旋转_01.png 需要实现的功能:

  • 系统关闭屏幕旋转且当前为正向竖屏或反向竖屏时,打开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()
    }
}