Activity手動(dòng)設(shè)置橫豎屏展示之后繼續(xù)保持橫豎屏自動(dòng)切換

今天項(xiàng)目中遇到一個(gè)問題,因?yàn)槲覀兊捻?xiàng)目有幾個(gè)視頻播放的界面裙犹,所以避不開與全屏/半屏按鈕伙判、鎖屏/解屏按鈕象对、方向傳感橫豎屏自動(dòng)變化打交道,我就被分到了這些任務(wù)宴抚。
先上一下大致的界面:

橫屏

豎屏

一般來說勒魔,涉及到能播放視頻的界面都大同小異(優(yōu)酷、愛奇藝等)菇曲,拋開彈幕冠绢、攝像頭、倍速羊娃、截屏唐全、截Gif等功能不談,幾乎都會(huì)有全屏/半屏播放蕊玷、鎖屏/解屏邮利、方向傳感這三個(gè)東西,而這三個(gè)東西都會(huì)牽涉到橫豎屏問題垃帅。

一開始的時(shí)候延届,我認(rèn)為很好做,也沒多想贸诚,覺得思路就是這樣:
⑴.全屏/半屏按鈕點(diǎn)擊邏輯:
監(jiān)測(cè)點(diǎn)擊全屏/半屏按鈕時(shí)方庭,用戶屏幕所處的橫豎位置,然后根據(jù)橫豎屏酱固,反向設(shè)置鎖定死用戶的屏幕:

/**
 * 橫豎屏切換
 */
private void changeScreenOrientation() {
    //獲取用戶當(dāng)前屏幕的橫豎位置
    int currentOrientation = getResources().getConfiguration().orientation;
    //判斷并設(shè)置用戶點(diǎn)擊全屏/半屏按鈕的顯示邏輯
    if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
        //如果屏幕當(dāng)前是橫屏顯示械念,則設(shè)置屏幕鎖死為豎屏顯示
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
        //如果屏幕當(dāng)前是豎屏顯示,則設(shè)置屏幕鎖死為橫屏顯示
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
}

⑵.鎖屏按鈕點(diǎn)擊邏輯:
當(dāng)點(diǎn)擊鎖屏按鈕時(shí)运悲,設(shè)置手機(jī)忽略方向傳感龄减;當(dāng)點(diǎn)擊解屏按鈕時(shí),設(shè)置手機(jī)恢復(fù)方向傳感班眯。

/**
 * 鎖定/解鎖屏幕點(diǎn)擊事件
 */
private void lockScreen(){
    if(mLockBtn.isChecked()){
        //鎖定屏幕
        //忽略物理方向傳感器希停,這樣就不會(huì)隨著用戶旋轉(zhuǎn)設(shè)備而橫豎屏切換了
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
    } else {
        //解鎖屏幕
        //由設(shè)備的物理方向傳感器決定烁巫,如果用戶旋轉(zhuǎn)設(shè)備,這屏幕就會(huì)橫豎屏切換
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
    }
}

⑶.方向傳感橫豎屏自動(dòng)變化邏輯
直接把這個(gè)界面在清單文件下設(shè)計(jì)一下即可:

<!-- 測(cè)試橫豎屏視頻播放界面 -->
<activity
    android:name=".modules.course.VodActivity"
    android:configChanges="orientation|screenSize|layoutDirection"
    android:screenOrientation="unspecified" />

但是誰知道里面的坑很深宠能,全然不是這么回事亚隙,寫完之后測(cè)試就找上門了,說:我沒鎖死屏幕违崇,點(diǎn)擊全屏播放了阿弃,為啥我又豎著拿手機(jī)屏幕不自動(dòng)切換回來了?
我擦亦歉,當(dāng)然不能自動(dòng)切換回來了恤浪,點(diǎn)擊全屏播放,我鎖死為手機(jī)橫屏了肴楷!

當(dāng)時(shí)覺得產(chǎn)品這個(gè)需求很不合理水由,又要全屏按鈕控制橫豎屏,又要小鎖按鈕控制橫豎屏赛蔫,還有手機(jī)方向感應(yīng)控制橫豎屏砂客,一旦我在代碼中強(qiáng)制設(shè)置屏幕的橫豎變化,不論是設(shè)置為ActivityInfo的哪個(gè)控制橫豎屏的值:

SCREEN_ORIENTATION_LANDSCAPE呵恢、
SCREEN_ORIENTATION_PORTRAIT鞠值、
SCREEN_ORIENTATION_SENSOR_LANDSCAPE、
SCREEN_ORIENTATION_SENSOR_PORTRAIT渗钉、
SCREEN_ORIENTATION_REVERSE_LANDSCAPE彤恶、
SCREEN_ORIENTATION_REVERSE_PORTRAIT、
SCREEN_ORIENTATION_USER_LANDSCAPE鳄橘、
SCREEN_ORIENTATION_USER_PORTRAIT

手機(jī)的方向感應(yīng)基本上算是都GG了声离。那點(diǎn)擊全屏/豎屏按鈕,強(qiáng)制設(shè)置了上面的值瘫怜,還怎么再讓手機(jī)方向感應(yīng)自動(dòng)變化呢术徊。
而且還有一個(gè)不合理的場(chǎng)景,如果用戶豎著拿手機(jī)鲸湃,點(diǎn)擊了界面的全屏播放赠涮,我設(shè)置界面為橫屏了,但此處如果方向傳感器還起作用的話暗挑,界面又立馬變回豎屏了笋除,那用戶覺得全屏按鈕還有啥作用呀。

:只能這么實(shí)現(xiàn)炸裆,沒法做到點(diǎn)擊全屏按鈕之后垃它,手機(jī)的方向傳感器還在繼續(xù)生效,就算繼續(xù)生效,也會(huì)立馬變回豎屏播放嗤瞎,相當(dāng)于全屏按鈕不好使。

:優(yōu)酷做出來了

:....

:愛奇藝也做出來了

:...那啥听系,我再看看吧贝奇。

下了個(gè)愛奇藝和優(yōu)酷,發(fā)現(xiàn)還真是做到了這個(gè)功能靠胜,他們的功能邏輯實(shí)現(xiàn)了方向感應(yīng)和全屏/半屏按鈕手動(dòng)設(shè)置的兼容掉瞳。對(duì)于上面的類似于功能沖突的點(diǎn),他們的做法是浪漠,如果用戶豎著拿手機(jī)陕习,點(diǎn)擊了界面的全屏播放,就會(huì)設(shè)置界面為橫屏顯示址愿,方向傳感器此時(shí)失效该镣,但是當(dāng)用戶拿著手機(jī)變化了一下位置,比如我豎著拿手機(jī)响谓,點(diǎn)擊了全屏损合,屏幕此時(shí)向左橫屏顯示,但是我拿著手機(jī)往右橫屏側(cè)過來娘纷,此時(shí)方向傳感器又起作用嫁审,把屏幕向右橫屏顯示。
好吧赖晶,用了一下午的時(shí)間在研究這個(gè)東西律适,發(fā)現(xiàn)不論怎么變換關(guān)鍵字,BD搜索到東西和這個(gè)功能沒一點(diǎn)關(guān)聯(lián)性遏插,全是在說怎么設(shè)置橫豎屏的問題捂贿,想念谷歌呀!

到后來自己摸索了一套方法涩堤,較為簡(jiǎn)單的解決了這個(gè)問題眷蜓!


首先必須得先了解一下ActivityInfo類的各個(gè)屬性值代表啥意思,不能亂用:

源碼:
@IntDef({
        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
})

挨個(gè)解釋一下(先找了這幾個(gè)胎围,剩下的有空搜到再一個(gè)個(gè)補(bǔ)充):

ActivityInfo屬性值 含義
SCREEN_ORIENTATION_UNSET
SCREEN_ORIENTATION_UNSPECIFIED 默認(rèn)值吁系,系統(tǒng)根據(jù)方向感應(yīng)自動(dòng)選擇屏幕方向
SCREEN_ORIENTATION_LANDSCAPE 正向橫屏,顯示的寬比高長(zhǎng)(鎖死為橫屏方向白魂,不再讓方向感應(yīng)起作用)
SCREEN_ORIENTATION_PORTRAIT 正向豎屏汽纤,顯示的高比寬長(zhǎng)(鎖死為豎屏方向,不再讓方向感應(yīng)起作用)
SCREEN_ORIENTATION_USER 用戶當(dāng)前首選的方向
SCREEN_ORIENTATION_BEHIND 這個(gè)有點(diǎn)奇葩福荸,它跟Activity堆棧中的下面一個(gè)Activity的方向一致
SCREEN_ORIENTATION_SENSOR 由設(shè)備的方向傳感器決定蕴坪,如果用戶旋轉(zhuǎn)設(shè)備,這屏幕就會(huì)橫豎屏切換(這里要注意了:這個(gè)屬性有些強(qiáng)悍。大家知道安卓手機(jī)上都有一個(gè)“屏幕旋轉(zhuǎn)”按鈕背传,有的也叫“鎖定屏幕”隨便什么名字不管了呆瞻,這個(gè)設(shè)置里面的開關(guān)和Activity有密切關(guān)系。關(guān)閉它之后Activity界面就不能響應(yīng)方向傳感器了径玖,打開它才會(huì)恢復(fù)正常痴脾,挺合理的一個(gè)功能,讓決定權(quán)放在用戶手中梳星≡蘩担可一旦你設(shè)置了這個(gè)屬性,無論用戶怎么設(shè)置自己的手機(jī)上的“屏幕旋轉(zhuǎn)”按鈕冤灾,打開也好前域,關(guān)閉也好,Activity界面都會(huì)響應(yīng)方向傳感器的韵吨,會(huì)隨著用戶手持手機(jī)的方向自動(dòng)變化匿垄,這就讓用戶有點(diǎn)奇怪。)
SCREEN_ORIENTATION_NOSENSOR 忽略物理方向傳感器归粉,這樣就不會(huì)隨著用戶旋轉(zhuǎn)設(shè)備而橫豎屏切換了(這里有個(gè)坑:如果用戶橫屏拿著手機(jī)進(jìn)行播放年堆,界面也是橫屏的,一旦設(shè)置了這個(gè)屬性之后盏浇,手機(jī)界面會(huì)先變換到豎屏变丧,然后才會(huì)鎖死方向傳感器)
SCREEN_ORIENTATION_SENSOR_LANDSCAPE 橫屏,和上面它“爸爸”SENSOR一樣強(qiáng)悍绢掰,無視用戶手機(jī)設(shè)置的“屏幕旋轉(zhuǎn)”按鈕開關(guān)痒蓬,直接根據(jù)方向傳感器來切換正反向橫屏,但是不會(huì)切換到豎屏
SCREEN_ORIENTATION_SENSOR_PORTRAIT 豎屏滴劲,和上面它“爸爸”SENSOR一樣強(qiáng)悍攻晒,無視用戶手機(jī)設(shè)置的“屏幕旋轉(zhuǎn)”按鈕開關(guān),直接根據(jù)方向傳感器來切換正反向豎屏班挖,不會(huì)切換到橫屏
SCREEN_ORIENTATION_REVERSE_LANDSCAPE 反向橫屏鲁捏,橫屏分正向橫屏(靠左手方向橫屏)和反向橫屏(靠右手方向橫屏)
SCREEN_ORIENTATION_REVERSE_PORTRAIT 反向豎屏,就是和正常豎著拿手機(jī)相反萧芙,豎著掉了個(gè)個(gè)
SCREEN_ORIENTATION_FULL_SENSOR
SCREEN_ORIENTATION_USER_LANDSCAPE
SCREEN_ORIENTATION_USER_PORTRAIT
SCREEN_ORIENTATION_FULL_USER
SCREEN_ORIENTATION_LOCKED 鎖死用戶當(dāng)前屏幕给梅,方向傳感器不生效(這里也有一個(gè)坑,低版本不生效双揪,如vivo4.1动羽,你如果使用這個(gè)屬性來鎖定屏幕,它會(huì)直接變回到豎屏再鎖死)

⑴首先先來分析全屏/半屏按鈕渔期,可以這么做:
還是順著之前的思路來走:

/**
 * 橫豎屏切換
 */
private void changeScreenOrientation() {
    //獲取用戶當(dāng)前屏幕的橫豎位置
    int currentOrientation = getResources().getConfiguration().orientation;
    //判斷并設(shè)置用戶點(diǎn)擊全屏/半屏按鈕的顯示邏輯
    if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
        //如果屏幕當(dāng)前是橫屏顯示运吓,則設(shè)置屏幕鎖死為豎屏顯示
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
        //如果屏幕當(dāng)前是豎屏顯示渴邦,則設(shè)置屏幕鎖死為橫屏顯示
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    }
}

設(shè)置完之后呢,發(fā)現(xiàn)手機(jī)的方向感應(yīng)器失效了拘哨。那全屏半屏問題是解決了谋梭,
但是,最重要的事情也來了倦青,我們需要在一個(gè)正確的“點(diǎn)”上恢復(fù)手機(jī)的方向感應(yīng)器章蚣!

⑵怎么來找這個(gè)點(diǎn)呢?
我們來想姨夹,按照優(yōu)酷的那個(gè)實(shí)現(xiàn)方法,豎屏拿著手機(jī)矾策,點(diǎn)擊全屏按鈕之后磷账,切換到橫屏,此時(shí)如果用戶不移動(dòng)手機(jī)或者移動(dòng)的幅度不大贾虽,屏幕還是橫屏逃糟,一旦動(dòng)作過大(比如我把手機(jī)橫過來了),此時(shí)你會(huì)發(fā)現(xiàn)蓬豁,方向感應(yīng)器又好使了绰咽!
就這么來實(shí)現(xiàn)它!
在這里介紹一個(gè)監(jiān)聽器OrientationEventListener地粪,可以用它來監(jiān)聽用戶的手機(jī)位置變化情況:

OrientationEventListener orientationListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {

    @Override
    public void onOrientationChanged(int orientation) {
        if(orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
            //手機(jī)平放時(shí)取募,檢測(cè)不到有效的角度
            return;
        }

        /**
         * 只檢測(cè)是否有四個(gè)角度的改變
         */
        if(orientation > 350 || orientation< 10) {
            //0度,用戶豎直拿著手機(jī)

        } else if(orientation > 80 && orientation < 100) {
            //90度蟆技,用戶右側(cè)(正向)橫屏拿著手機(jī)

        } else if(orientation > 170 && orientation < 190) {
            //180度玩敏,用戶反向豎直拿著手機(jī)

        } else if(orientation > 260 && orientation < 280) {
            //270度,用戶左側(cè)(反向)橫屏拿著手機(jī)
        }
    }
};

對(duì)應(yīng)的具體方位圖:


0度质礼,用戶豎直拿著手機(jī)
90度旺聚,用戶右側(cè)橫屏拿著手機(jī)
180度,用戶反向豎直拿著手機(jī)
270度眶蕉,用戶左側(cè)橫屏拿著手機(jī)

有了這個(gè)監(jiān)聽器砰粹,就變得很簡(jiǎn)單了。
我們可以這樣造挽,在onOrientationChanged(int orientation)實(shí)時(shí)記錄用戶的位置碱璃,看是否與記錄的用戶手機(jī)上一次手機(jī)所處的位置發(fā)生了改變,如果改變了饭入,則用戶手機(jī)發(fā)生了很大的位置偏移厘贼,就需要恢復(fù)用戶手機(jī)的方向傳感器。

@Override
public void onOrientationChanged(int orientation) {
        //判null
        if(mActivity == null || mActivity.isFinishing()){
            return;
        }
        //記錄用戶手機(jī)上一次放置的位置
        int mLastOrientation = mOrientation;

        if(orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
            //手機(jī)平放時(shí)圣拄,檢測(cè)不到有效的角度

            //重置為原始位置 -1
            mOrientation = -1;
            return;
        }

        /**
         * 只檢測(cè)是否有四個(gè)角度的改變
         */
        if(orientation > 350 || orientation< 10) {
            //0度嘴秸,用戶豎直拿著手機(jī)
            mOrientation = 0;

        } else if(orientation > 80 && orientation < 100) {
            //90度,用戶右側(cè)橫屏拿著手機(jī)
            mOrientation = 90;

        } else if(orientation > 170 && orientation < 190) {
            //180度,用戶反向豎直拿著手機(jī)
            mOrientation = 180;

        } else if(orientation > 260 && orientation < 280) {
            //270度岳掐,用戶左側(cè)橫屏拿著手機(jī)
            mOrientation = 270;
        }

        //如果用戶鎖定了屏幕凭疮,不再開啟代碼自動(dòng)旋轉(zhuǎn)了,直接return
        if(mIsLock){
            return;
        }

        //如果用戶關(guān)閉了手機(jī)的屏幕旋轉(zhuǎn)功能串述,不再開啟代碼自動(dòng)旋轉(zhuǎn)了执解,直接return
        try {
            /**
             * 1 手機(jī)已開啟屏幕旋轉(zhuǎn)功能
             * 0 手機(jī)未開啟屏幕旋轉(zhuǎn)功能
             */
            if(Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0){
                return;
            }
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }

        //當(dāng)檢測(cè)到用戶手機(jī)位置距離上一次記錄的手機(jī)位置發(fā)生了改變,開啟屏幕自動(dòng)旋轉(zhuǎn)
        if(mLastOrientation != mOrientation){
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        }
    }

大頭搞定纲酗,剩下的就簡(jiǎn)單了衰腌,完善其他小邏輯。
⑶手機(jī)本身的方向傳感器
這個(gè)簡(jiǎn)單觅赊,可以直接在AndroidManifest.xml中設(shè)置SCREEN_ORIENTATION_UNSPECIFIED屬性就可以了右蕊,剩下的,交給OrientationEventListener小鎖的邏輯重新對(duì)其賦值即可

<activity
    android:name=".modules.course.DemoActivity"
    android:configChanges="orientation|screenSize|layoutDirection"
    android:screenOrientation="unspecified" />

⑷小鎖的邏輯
檢測(cè)下小鎖的開關(guān)是否打開吮螺,如果打開饶囚,就放開手機(jī)方向感應(yīng)器(前提是用戶打開了自己手機(jī)上的自動(dòng)旋轉(zhuǎn));如果關(guān)閉鸠补,就是鎖死手機(jī)方向感應(yīng)器:

/**
 * 鎖定/解鎖屏幕點(diǎn)擊事件
 */
private void lockScreen(){
    if(mLockBtn.isChecked()){
        //鎖定屏幕
        //獲取用戶當(dāng)前屏幕的橫豎位置
        int currentOrientation = getResources().getConfiguration().orientation;
        //判斷并設(shè)置用戶點(diǎn)擊鎖定屏幕按鈕的顯示邏輯
        if(currentOrientation == Configuration.ORIENTATION_LANDSCAPE){
            //如果屏幕當(dāng)前是橫屏顯示萝风,則設(shè)置屏幕鎖死為橫屏顯示
            
            if(mMyOrientationDetector.getDisplayRotation() == 90){
                //正向橫屏
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
             } else if(mMyOrientationDetector.getDisplayRotation() == 270){
                //反向橫屏
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
             }
        } else if(currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
            //如果屏幕當(dāng)前是豎屏顯示,則設(shè)置屏幕鎖死為豎屏顯示
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    } else {
        //解鎖屏幕
        try {
            /**
             * 1 手機(jī)已開啟屏幕旋轉(zhuǎn)功能
             * 0 手機(jī)未開啟屏幕旋轉(zhuǎn)功能
             */
            if(Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 1){
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
            }
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
    }
}

其中紫岩,getDisplayRotation() 是一個(gè)檢測(cè)手機(jī)正反向橫豎屏的方法:

/**
     * 獲取當(dāng)前屏幕旋轉(zhuǎn)角度
     *
     * @return
     *
     * 0 - 表示是豎屏  90 - 表示是左橫屏(正向)  180 - 表示是反向豎屏  270表示是右橫屏(反向)
     */
    public int getDisplayRotation() {

        int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
        switch (rotation) {
            case Surface.ROTATION_0:
                return 0;
            case Surface.ROTATION_90:
                return 90;
            case Surface.ROTATION_180:
                return 180;
            case Surface.ROTATION_270:
                return 270;
        }
        return 0;
    }

這里在贅述一點(diǎn)规惰,當(dāng)時(shí)我想的是:
①鎖定屏幕,直接設(shè)置SCREEN_ORIENTATION_NOSENSOR泉蝌,不再這么麻煩的先去判斷屏幕正反向橫豎屏卿拴,再去分別鎖死,但是這里面具體實(shí)現(xiàn)起來發(fā)現(xiàn)了個(gè)坑梨与,如果用戶橫屏拿著手機(jī)進(jìn)行播放堕花,界面也是橫屏的,一旦設(shè)置了這個(gè)屬性之后粥鞋,手機(jī)界面會(huì)先變換到豎屏缘挽,然后才會(huì)鎖死方向傳感器。
②鎖定屏幕呻粹,直接設(shè)置SCREEN_ORIENTATION_LOCKED壕曼,不再這么麻煩的先去判斷屏幕正反向橫豎屏,再去分別鎖死等浊,但是這里面也發(fā)現(xiàn)了個(gè)坑腮郊,這個(gè)屬性在低版本手機(jī)上不生效,它也會(huì)直接變回到豎屏再鎖死
③鎖定屏幕筹燕,判斷橫豎屏再進(jìn)行鎖死:

if(mLockBtn.isChecked()){
    //鎖定屏幕
    //獲取用戶當(dāng)前屏幕的橫豎位置
    int currentOrientation = getResources().getConfiguration().orientation;
    //判斷并設(shè)置用戶點(diǎn)擊鎖定屏幕按鈕的顯示邏輯
    if(currentOrientation == Configuration.ORIENTATION_LANDSCAPE){
        //如果屏幕當(dāng)前是橫屏顯示轧飞,則設(shè)置屏幕鎖死為橫屏顯示
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    } else if(currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
        //如果屏幕當(dāng)前是豎屏顯示衅鹿,則設(shè)置屏幕鎖死為豎屏顯示
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }
}

但是這樣的話,也有一個(gè)bug:
我在上面介紹各個(gè)屬性的時(shí)候过咬,說過橫屏分為正向橫屏和反向橫屏大渤,豎屏同理。
此時(shí)如果用戶是反向橫屏拿著手機(jī)的掸绞,代碼這么寫的話泵三,直接設(shè)置SCREEN_ORIENTATION_LANDSCAPE,手機(jī)屏幕會(huì)直接翻轉(zhuǎn)到正向橫屏再鎖死衔掸,讓用戶感到奇怪烫幕。
以上就是我做鎖定屏幕的時(shí)候,經(jīng)歷的種種探索敞映,感覺好麻煩较曼,但是做出來還是挺開心的。


OK驱显,到了這里,就把三個(gè)邏輯融合到一起了瞳抓。最后再優(yōu)化優(yōu)化邏輯(大體思路就是上面的這些東西)埃疫、封裝成一個(gè)工具類:

/**
 * 自定義工具類
 *
 * 實(shí)時(shí)的檢測(cè)用戶屏幕的位置改變,做到 重力感應(yīng) 與 全屏/半屏按鈕 邏輯的互容
 */
public class CLOrientationDetector extends OrientationEventListener {

    /**
     * 橫豎屏BaseActivity
     */
    private BaseActivity mActivity;
    /**
     * 用戶是否鎖定屏幕
     */
    private boolean mIsLock = false;
    /**
     * 實(shí)時(shí)記錄用戶手機(jī)屏幕的位置
     */
    private int mOrientation = -1;

    /**
     * 構(gòu)造方法
     * @param activity
     */
    public CLOrientationDetector(BaseActivity activity) {
        super(activity);
        mActivity = activity;
    }

    /**
     * 設(shè)置用戶屏幕是否被鎖定
     * @param isLock
     */
    public void setIsLock(boolean isLock){
        mIsLock = isLock;
    }

    @Override
    public void onOrientationChanged(int orientation) {
        //判null
        if(mActivity == null || mActivity.isFinishing()){
            return;
        }
        //記錄用戶手機(jī)上一次放置的位置
        int mLastOrientation = mOrientation;

        if(orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
            //手機(jī)平放時(shí)孩哑,檢測(cè)不到有效的角度

            //重置為原始位置 -1
            mOrientation = -1;
            return;
        }

        /**
         * 只檢測(cè)是否有四個(gè)角度的改變
         */
        if(orientation > 350 || orientation< 10) {
            //0度栓霜,用戶豎直拿著手機(jī)
            mOrientation = 0;

        } else if(orientation > 80 && orientation < 100) {
            //90度,用戶右側(cè)橫屏拿著手機(jī)
            mOrientation = 90;

        } else if(orientation > 170 && orientation < 190) {
            //180度横蜒,用戶反向豎直拿著手機(jī)
            mOrientation = 180;

        } else if(orientation > 260 && orientation < 280) {
            //270度胳蛮,用戶左側(cè)橫屏拿著手機(jī)
            mOrientation = 270;
        }

        //如果用戶鎖定了屏幕,不再開啟代碼自動(dòng)旋轉(zhuǎn)了丛晌,直接return
        if(mIsLock){
            return;
        }

        //如果用戶關(guān)閉了手機(jī)的屏幕旋轉(zhuǎn)功能仅炊,不再開啟代碼自動(dòng)旋轉(zhuǎn)了,直接return
        try {
            /**
             * 1 手機(jī)已開啟屏幕旋轉(zhuǎn)功能
             * 0 手機(jī)未開啟屏幕旋轉(zhuǎn)功能
             */
            if(Settings.System.getInt(mActivity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION) == 0){
                return;
            }
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }

        //當(dāng)檢測(cè)到用戶手機(jī)位置距離上一次記錄的手機(jī)位置發(fā)生了改變澎蛛,開啟屏幕自動(dòng)旋轉(zhuǎn)
        if(mLastOrientation != mOrientation){
            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        }
    }

    /**
     * 獲取當(dāng)前屏幕旋轉(zhuǎn)角度
     *
     * @return
     *
     * 0 - 表示是豎屏  90 - 表示是左橫屏(正向)  180 - 表示是反向豎屏  270表示是右橫屏(反向)
     */
    public int getDisplayRotation() {

        int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
        switch (rotation) {
            case Surface.ROTATION_0:
                return 0;
            case Surface.ROTATION_90:
                return 90;
            case Surface.ROTATION_180:
                return 180;
            case Surface.ROTATION_270:
                return 270;
        }
        return 0;
    }
}

這篇文章說的比較簡(jiǎn)單抚垄,主要想表明的就是這個(gè)思路,思路有了谋逻,就上手代碼就容易了呆馁。小伙伴們?nèi)绻懈玫乃悸返脑挘瑲g迎指正毁兆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浙滤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子气堕,更是在濱河造成了極大的恐慌纺腊,老刑警劉巖畔咧,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異摹菠,居然都是意外死亡盒卸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門次氨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔽介,“玉大人,你說我怎么就攤上這事煮寡『缧睿” “怎么了?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵幸撕,是天一觀的道長(zhǎng)薇组。 經(jīng)常有香客問我,道長(zhǎng)坐儿,這世上最難降的妖魔是什么律胀? 我笑而不...
    開封第一講書人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮貌矿,結(jié)果婚禮上炭菌,老公的妹妹穿的比我還像新娘。我一直安慰自己逛漫,他們只是感情好黑低,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酌毡,像睡著了一般克握。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枷踏,一...
    開封第一講書人閱讀 49,729評(píng)論 1 289
  • 那天菩暗,我揣著相機(jī)與錄音,去河邊找鬼旭蠕。 笑死勋眯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的下梢。 我是一名探鬼主播客蹋,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼孽江!你這毒婦竟也來了讶坯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤岗屏,失蹤者是張志新(化名)和其女友劉穎辆琅,沒想到半個(gè)月后漱办,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡婉烟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年娩井,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片似袁。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洞辣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昙衅,到底是詐尸還是另有隱情扬霜,我是刑警寧澤,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布而涉,位于F島的核電站著瓶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏啼县。R本人自食惡果不足惜材原,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望季眷。 院中可真熱鬧余蟹,春花似錦、人聲如沸瘟裸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)话告。三九已至,卻和暖如春卵慰,著一層夾襖步出監(jiān)牢的瞬間沙郭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工裳朋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留病线,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓鲤嫡,卻偏偏與公主長(zhǎng)得像送挑,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子暖眼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容