关于 fragmentation 如何只让某个Fragment支持横屏

众所周知,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);
    }

你可能感兴趣的:(关于 fragmentation 如何只让某个Fragment支持横屏)