Android 屏幕方向相关,setRequestedOrientation,OrientationEventListener

1 Activity 在AndroidManifest.xml设置方向android:screenOrientation

正向拿着手机(平时正常拿手机)对应角度为0度,此时屏幕为为竖屏,旋转180度,对应角度180度,此时屏幕为反向竖屏;
90时此时屏幕为横屏(用户右侧(正向)横屏拿着手机),屏幕角度为270,此时屏幕为反向横屏。
Android可以利用android:screenOrientation控制activity启动时方向,取值可以为:
在这里插入图片描述
常见属性解释:
unspecified,默认值,由系统决定,不同手机可能不一致,设置了这个属性会根据手机本身的传感器方向变化。
landscape,强制横屏显示
portrait,强制竖屏显
“reverselandscape” 与正常的横向方向相反显示。
“reverseportrait” 与正常的纵向方向相反显示。
behind,与前一个activity方向相同
“sensor” 根据设备传感器方向设置屏幕方向,当用户旋转设备时,显示的方向会改变。但默认情况下,有些设备不会在所有的四个方向上都旋转,因此要允许在所有的四个方向上都能旋转,就要使用fullsensor属性值。
“fullsensor” 显示的方向(4个方向)是由设备的方向传感器来决定的,除了它允许屏幕有4个显示方向之外,其他与设置为“sensor”时情况类似。
sensorLandscape,横屏旋转,一般横屏游戏会这样设置
sensorPortrait,竖屏旋转
nosensor,旋转设备时候,界面不会跟着旋转。初始化界面方向由系统控制
user,用户当前设置的方向

引用总结(https://www.jianshu.com/p/dd53094b580a 感谢作者):
ActivityInfo属性值 含义
SCREEN_ORIENTATION_UNSET
SCREEN_ORIENTATION_UNSPECIFIED 默认值,系统根据方向感应自动选择屏幕方向
SCREEN_ORIENTATION_LANDSCAPE 正向横屏,显示的宽比高长(锁死为横屏方向,不再让方向感应起作用)
SCREEN_ORIENTATION_PORTRAIT 正向竖屏,显示的高比宽长(锁死为竖屏方向,不再让方向感应起作用)
SCREEN_ORIENTATION_USER 用户当前首选的方向
SCREEN_ORIENTATION_BEHIND 这个有点奇葩,它跟Activity堆栈中的下面一个Activity的方向一致
SCREEN_ORIENTATION_SENSOR 由设备的方向传感器决定,如果用户旋转设备,这屏幕就会横竖屏切换(这里要注意了:这个属性有些强悍。大家知道安卓手机上都有一个“屏幕旋转”按钮,有的也叫“锁定屏幕”随便什么名字不管了,这个设置里面的开关和Activity有密切关系。关闭它之后Activity界面就不能响应方向传感器了,打开它才会恢复正常,挺合理的一个功能,让决定权放在用户手中。可一旦你设置了这个属性,无论用户怎么设置自己的手机上的“屏幕旋转”按钮,打开也好,关闭也好,Activity界面都会响应方向传感器的,会随着用户手持手机的方向自动变化,这就让用户有点奇怪。)
SCREEN_ORIENTATION_NOSENSOR 忽略物理方向传感器,这样就不会随着用户旋转设备而横竖屏切换了(这里有个坑:如果用户横屏拿着手机进行播放,界面也是横屏的,一旦设置了这个属性之后,手机界面会先变换到竖屏,然后才会锁死方向传感器)
SCREEN_ORIENTATION_SENSOR_LANDSCAPE 横屏,和上面它“爸爸”SENSOR一样强悍,无视用户手机设置的“屏幕旋转”按钮开关,直接根据方向传感器来切换正反向横屏,但是不会切换到竖屏
SCREEN_ORIENTATION_SENSOR_PORTRAIT 竖屏,和上面它“爸爸”SENSOR一样强悍,无视用户手机设置的“屏幕旋转”按钮开关,直接根据方向传感器来切换正反向竖屏,不会切换到横屏
SCREEN_ORIENTATION_REVERSE_LANDSCAPE 反向横屏,横屏分正向横屏(靠左手方向横屏)和反向横屏(靠右手方向横屏)
SCREEN_ORIENTATION_REVERSE_PORTRAIT 反向竖屏,就是和正常竖着拿手机相反,竖着掉了个个
SCREEN_ORIENTATION_FULL_SENSOR
SCREEN_ORIENTATION_USER_LANDSCAPE
SCREEN_ORIENTATION_USER_PORTRAIT
SCREEN_ORIENTATION_FULL_USER
SCREEN_ORIENTATION_LOCKED 锁死用户当前屏幕,方向传感器不生效(这里也有一个坑,低版本不生效,如vivo4.1,你如果使用这个属性来锁定屏幕,它会直接变回到竖屏再锁死)

对应角度
android:screenOrientation="landscape"为90度(横屏)
android:screenOrientation="reverseLandscape"为270度(反向横屏)
android:screenOrientation="sensorLandscape"为90度和270度根据G-sensor切换(横屏切换)
android:screenOrientation="portrait"为0度(竖屏)
android:screenOrientation="reversePortrait"为180度(反向竖屏)
android:screenOrientation=“sensorPortrait”为0度和180度之间切换(竖屏切换)

android:configChanges

上面的属性一般需要配合android:configChanges使用,如果不设置android:configChanges,在activity页面配置修改时,activity会被重新创建,配置了对应的android:configChanges,activity不会被重建,而是会调用Activity 的onConfigurationChanged()方法。
在这里插入图片描述
其中keyboard,keyboardHidden,orientation,screenSize,fontScale等都是常用属性。
android:configChanges=“orientation|keyboard|mcc|mnc|locale|keyboardHidden|uiMode|fontScale|keyboardHidden|screenSize”

说明:
设置了android:screenOrientation=“portrait”,或者landscape等相关属性(和setRequestedOrientation 设置效果相同),onConfigurationChanged属性不会被调用。

设置为sensor时,会跟随传感器方向改变activity方向,onConfigurationChanged被调用,
/**
* Overall orientation of the screen. May be one of
* {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
*/
public int orientation;

注意:设置了sensor后不是设备的每个方向都支持,类似pixel 2XL 反向竖屏就不支持,需要fullSensor属性才支持。

2 setRequestedOrientation 设置屏幕方向

 /**
     * Change the desired orientation of this activity.  If the activity
     * is currently in the foreground or otherwise impacting the screen
     * orientation, the screen will immediately be changed (possibly causing
     * the activity to be restarted). Otherwise, this will be used the next
     * time the activity is visible.
     *
     * @param requestedOrientation An orientation constant as used in
     * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}.
     */
    public void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
        if (mParent == null) {
            try {
                ActivityManager.getService().setRequestedOrientation(
                        mToken, requestedOrientation);
            } catch (RemoteException e) {
                // Empty
            }
        } else {
            mParent.setRequestedOrientation(requestedOrientation);
        }
    }

**所有取值**
  /** @hide */
    @IntDef(prefix = { "SCREEN_ORIENTATION_" }, value = {
            SCREEN_ORIENTATION_UNSET,
            SCREEN_ORIENTATION_UNSPECIFIED,
            SCREEN_ORIENTATION_LANDSCAPE,
            SCREEN_ORIENTATION_PORTRAIT,
            SCREEN_ORIENTATION_USER,
            SCREEN_ORIENTATION_BEHIND,
            SCREEN_ORIENTATION_SENSOR,
            SCREEN_ORIENTATION_NOSENSOR,
            SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
            SCREEN_ORIENTATION_SENSOR_PORTRAIT,
            SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
            SCREEN_ORIENTATION_REVERSE_PORTRAIT,
            SCREEN_ORIENTATION_FULL_SENSOR,
            SCREEN_ORIENTATION_USER_LANDSCAPE,
            SCREEN_ORIENTATION_USER_PORTRAIT,
            SCREEN_ORIENTATION_FULL_USER,
            SCREEN_ORIENTATION_LOCKED
    })

使用:

 <activity android:name=".activity.Main16Activity"
            android:configChanges="orientation|keyboard|mcc|mnc|locale|keyboardHidden|uiMode|fontScale|keyboardHidden|screenSize"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


public class Main16Activity extends AppCompatActivity {

    private Button btn1;
    private Button btn2;
    private Button btn3;
    private Button btn4;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main16);
        btn1 = findViewById(R.id.btn_portrait);
        btn2 = findViewById(R.id.btn_revert_portrait);
        btn3 = findViewById(R.id.btn_landscape);
        btn4 = findViewById(R.id.btn_revert_landscape);
        btn1.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        });
        btn2.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        });
        btn3.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        });
        btn4.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
        });
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        System.out.println("=========orientation=========="+newConfig.orientation);
    }
}

得到的结果可能每个人测试的有所不同,这时因为手机有一个方向锁定的功能,或者是自动旋转,叫法可能不同,
小米:
在这里插入图片描述
pixel
在这里插入图片描述
上面小米和pixel手机的开关是相反的,我们根据小米手机的文字来说明,当选中方向锁定时,此时方向会被锁定。方向锁定分两种,手机横屏时方向被锁定,手机竖屏时方向被锁定。方向被锁定之后,再次使用setRequestedOrientation时,不同手机可能表现有所不同。

pixel未被锁定时,setRequestedOrientation四个方向都可以设置,都有效。
pixel竖屏时被锁定(0)和pixel横屏时被锁定(180)效果相同,setRequestedOrientation REVERSE_PORTRAIT 和Portrait 作用相同,其他有效。
在这里插入图片描述

在这里插入图片描述

小米8 未被锁定时和竖屏锁定时(0),setRequestedOrientation REVERSE_PORTRAIT 和Portrait 作用相同,其他有效。
小米8横屏时被锁定(180),setRequestedOrientation 横屏 和反向横屏作用相同,竖屏和反向竖屏作用相同。
小米8就无法直接从竖屏转换到反向竖屏。

屏幕方向锁定获取:

Settings.System.getInt( context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION );
结果为1时没有被锁定,也就是开启了自动旋转。

3 获取屏幕旋转角度OrientationEventListener

调用this.getWindowManager().getDefaultDisplay().getRotation();
该函数的返回值,有如下四种:
Surface.ROTATION_0,Surface.ROTATION_90,Surface.ROTATION_180,Surface.ROTATION_270 代表了屏幕的方向。

其中,Surface.ROTATION_0 表示的是手机竖屏方向向上,后面几个以此为基准依次以顺时针90度递增。
设置了screenOrientation为sensor后,屏幕可以随着手机方向改变而改变,但当设置了屏幕方向为横屏或者竖屏之后,屏幕就不会再响应屏幕方向的改变,因为setRequestedOrientation和android:screenOrientation="portrait"效果相同,设置之后只能是横屏或者竖屏。

系统提供了OrientationEventListener用来监听屏幕旋转的角度,原理是利用加速度传感器。
使用方法:

public class Main16Activity extends AppCompatActivity {

    private Button btn1;
    private Button btn2;
    private Button btn3;
    private Button btn4;
    private Button btn5;
    private int mCurrentOrientation;

    OrientationEventListener mOrientationListener ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main16);
        btn1 = findViewById(R.id.btn_portrait);
        btn2 = findViewById(R.id.btn_revert_portrait);
        btn3 = findViewById(R.id.btn_landscape);
        btn4 = findViewById(R.id.btn_revert_landscape);
        btn5 = findViewById(R.id.btn_5);
        btn1.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        });
        btn2.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
        });
        btn3.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        });
        btn4.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
        });

        btn5.setOnClickListener(view -> {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        });

        //简单判断和操作,详细的可用方法需要结合方向锁定,activity变化之前的方向
        mOrientationListener = new OrientationEventListener(this) {
            @Override
            public void onOrientationChanged(int degree) {
                //此处依据degress判断横竖屏,可以根据自己的需要进行判断是横屏还是竖屏。

               // System.out.println("=========degree=============="+degree);

                //手机平放时,检测不到有效的角度
                if ( degree == OrientationEventListener.ORIENTATION_UNKNOWN ) {
                    return;
                }

                if ( degree >= 350 || degree <= 20 ) {
                    //0度,用户竖直拿着手机
                    mCurrentOrientation = 0;
                    System.out.println("=========0=============="+degree);
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                } else if ( degree >= 70 && degree <= 110 ) {
                    //90度,用户右侧横屏拿着手机
                    mCurrentOrientation = 90;
                    System.out.println("=========90=============="+degree);
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                } else if ( degree >= 160 && degree <= 200 ) {
                    //180度,用户反向竖直拿着手机
                    mCurrentOrientation = 180;
                    System.out.println("=========180=============="+degree);
                    //很多手机不起作用,类似小米8
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
                } else if ( degree >= 250 && degree <= 290 ) {
                    //270度,用户左侧横屏拿着手机
                    mCurrentOrientation = 270;
                    System.out.println("=========270=============="+degree);
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                }else{
                    return;
                }

            }
        };

        if (mOrientationListener.canDetectOrientation()) {//判断设备是否支持
            mOrientationListener.enable();
        } else {
            mOrientationListener.disable();//注销
            //当前设备不支持手机旋转!
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        System.out.println("=========orientation=========="+newConfig.orientation);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mOrientationListener != null){
            mOrientationListener.disable();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mOrientationListener != null){
            mOrientationListener.enable();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mOrientationListener != null){
            mOrientationListener.disable();
        }
    }

    private boolean isLock(){
        try {
            int flag = Settings.System.getInt( Main16Activity.this.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION );
            if (flag == 1)return false;
            return true;
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
            return false;
        }
    }
}

android 屏幕方向随传感器变化,并带有切换大屏,小屏和锁定屏幕方向

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值