開發(fā)時遇到播放視頻要用重力感應(yīng)來橫豎屏漩氨,并且要有按鈕點擊橫豎屏西壮,查了很多資料,并參考了網(wǎng)上一些實現(xiàn)思路叫惊,終于把重力感應(yīng)橫豎屏完整實現(xiàn)款青,現(xiàn)封裝成工具類,可以直接使用霍狰。
一抡草、實現(xiàn)原理
既然是重力感應(yīng)橫豎屏,那就肯定要有重力感應(yīng)蔗坯,重力感應(yīng)屬于傳感器的一類康震,所以需要用到重力感應(yīng)傳感器,不清楚的同學(xué)可以google一下步悠。
由于視頻播放或者直播頁面一直都需要重力感應(yīng)签杈,所以還需要綁定播放頁面的生命周期來注冊重力感應(yīng)和注銷重力感應(yīng)。這樣當(dāng)注冊重力感應(yīng)后鼎兽,就可以獲取當(dāng)前屏幕的朝向角度答姥,根據(jù)這些角度來判斷哪個范圍需要橫豎屏。
二谚咬、實現(xiàn)邏輯
2.1 打造工具類ScreenRotateUtils
由于要綁定生命周期鹦付,并且可以點擊橫豎屏,所以可以做一個工具類择卦,提供start()和stop方法來綁定生命周期敲长,并且暴露一個點擊切換橫豎屏的方法toggleRotate()就可以。
-
start方法注冊監(jiān)聽
public void start(Activity activity) { // 接收activity秉继,用于操作屏幕的旋轉(zhuǎn) mActivity = activity; // 注冊傳感器監(jiān)聽 sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI); }
-
stop()方法注銷監(jiān)聽
public void stop() { // 注銷監(jiān)聽 sm.unregisterListener(listener); // 防止內(nèi)存泄漏 mActivity = null; }
-
toggleRotate()方法祈噪,自動切換橫豎屏
public void toggleRotate() { /** * 先判斷是否已經(jīng)開啟了重力感應(yīng),沒開啟就直接普通的切換橫豎屏 */ if(isEffetSysSetting){ try { int isRotate = Settings.System.getInt(mActivity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION); // 如果用戶禁用掉了重力感應(yīng)就直接切換 if (isRotate == 0) { changeOrientation(isLandscape, true); return; } } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } } /** * 如果開啟了重力感應(yīng)就需要修改狀態(tài) */ isOpenSensor = false; isClickFullScreen = true; if (isChangeOrientation) { changeOrientation(isLandscape, false); } else { isLandscape = !isLandscape; changeOrientation(isLandscape, false); } }
2.2 重力感應(yīng)傳感器
Android提供了多種傳感器尚辑,這里只是簡單介紹一下重力感應(yīng)傳感器辑鲤,想了解更多請傳送。
-
初始化傳感器
// 這里在構(gòu)造里初始化重力重力感應(yīng) private ScreenRotateUtil(Context context) { // 獲取傳感器管理器 sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); // 獲取傳感器類型 sensor = sm.getDefaultSensor(Sensor.TYPE_GRAVITY); // 初始化監(jiān)聽器 listener = new OrientationSensorListener(mHandler); }
start()方法注冊監(jiān)聽杠茬,stop()方法注銷監(jiān)聽
-
看一下監(jiān)聽里非常重要的方法onSensorChanged月褥,當(dāng)注冊了監(jiān)聽后弛随,這個方法會不停的回調(diào)用,不停的給Handler發(fā)送消息宁赤,然后就可以在Handler里修改屏幕的朝向舀透。
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) { // 屏幕旋轉(zhuǎn)時 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; } } /** * 獲取手機(jī)系統(tǒng)的重力感應(yīng)開關(guān)設(shè)置,這段代碼看需求决左,不要就刪除 * screenchange = 1 表示開啟愕够,screenchange = 0 表示禁用 * 要是禁用了就直接返回 */ if(isEffetSysSetting){ try { int isRotate = Settings.System.getInt(mActivity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION); // 如果用戶禁用掉了重力感應(yīng)就直接return if (isRotate == 0) return; } catch (Settings.SettingNotFoundException e) { e.printStackTrace(); } } // 只有點了按鈕時才需要根據(jù)當(dāng)前的狀態(tài)來更新狀態(tài) if (isClickFullScreen) { if (isLandscape && screenIsPortrait(orientation)) { // 之前是橫屏,并且當(dāng)前是豎屏的狀態(tài) Log.d(TAG, "onSensorChanged: 橫屏 ----> 豎屏"); updateState(false, false, true, true); } else if (!isLandscape && screenIsLandscape(orientation)) { // 之前是豎屏哆窿,并且當(dāng)前是橫屏的狀態(tài) Log.d(TAG, "onSensorChanged: 豎屏 ----> 橫屏"); updateState(true, false, true, true); } else if (isLandscape && screenIsLandscape(orientation)) { // 之前是橫屏链烈,現(xiàn)在還是橫屏的狀態(tài) Log.d(TAG, "onSensorChanged: 橫屏 ----> 橫屏"); isChangeOrientation = false; } else if (!isLandscape && screenIsPortrait(orientation)) { // 之前是豎屏,現(xiàn)在還是豎屏的狀態(tài) Log.d(TAG, "onSensorChanged: 豎屏 ----> 豎屏"); isChangeOrientation = false; } } // 判斷是否要進(jìn)行中斷信息傳遞 if (!isOpenSensor) { return; } if (rotateHandler != null) { rotateHandler.obtainMessage(888, orientation, 0).sendToTarget(); } }
2.3 橫豎屏處理
-
這里的橫豎屏是去根據(jù)當(dāng)前手機(jī)的朝向即orientation的角度進(jìn)行判斷挚躯,然后調(diào)用mActivity.setRequestedOrientation()方法設(shè)置橫豎屏强衡,這里進(jìn)行了360°的判斷,實現(xiàn)了四個方向的橫豎屏码荔。
if (msg.what == 888) { int orientation = msg.arg1; /** * 根據(jù)手機(jī)屏幕的朝向角度漩勤,來設(shè)置內(nèi)容的橫豎屏,并且記錄狀態(tài) */ 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; } }
三缩搅、使用教程
- Activity的onResume()方法調(diào)用start()方法進(jìn)行注冊監(jiān)聽
- Activity的onPause()方法調(diào)用stop()方法注銷監(jiān)聽
- 點擊全屏按鈕時調(diào)用toggleRotate()自動切換橫豎屏
- 如果需要手機(jī)系統(tǒng)的橫豎屏按鈕生效則調(diào)用setEffectSysSetting(true)