最近在作播放器的時候遇到一個問題,在屏幕方向改變以後須要切換播放器全屏/非全屏的時候,在重寫了onConfigurationChanged方法並在manifest.xml配置文件中添加android
android:screenOrientation="sensor"ide
android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"ui
以後,在屏幕方向改變以後確實切換了播放器的方向,可是在個人程序中,須要一個播放器控制按鈕,當用戶點擊按鈕時手動切換播放器方向(即播放器全屏/小屏狀態切換)和屏幕方向改變時自動切換兩個功能並存;最開始想的是直接使用setRequestedOrientation()設置屏幕方向應該就OK了,可是發現這樣作是行不通的.以後瞭解到由於setRequestedOrientation設置屏幕方向以後,好比說setRequestedOrientation(portrait)方法,就設定了屏幕方向是portrait,和在清單文件中配置android:screenOrientation="portrait"是同等的效果;也即再也不響應屏幕方向改變,只支持portrait方向;this
言歸正轉,說個人處理方法,android給咱們提供了OrientationEventListener,從字面意思就知道是幹什麼用的;這個監聽器有一個onOrientationChanged(int rotation)方法會將當前屏幕旋轉的度數返回給用戶;spa
先看持接口中方法返回的旋轉度數的計算方法;code
上圖中金色區域就是手機,角度就是綠線和紅線之間的角度,順時針旋轉手機,角度增大,角度範圍0-360;手機平放的角度爲-1;orm
下面分別是橫屏和豎屏的界面,按鈕即用於切換屏幕方向;xml
再看看具體實現:接口
1.聲明變量事件
private OrientationEventListener mOrientationListener; // 屏幕方向改變監聽器 private boolean mIsLand = false; // 是不是橫屏 private boolean mClick = false; // 是否點擊 private boolean mClickLand = true; // 點擊進入橫屏 private boolean mClickPort = true; // 點擊進入豎屏
2.初始化監聽器
/** * 開啓監聽器 */ private final void startListener() { mOrientationListener = new OrientationEventListener(this) { @Override public void onOrientationChanged(int rotation) { // 設置豎屏 if (((rotation >= 0) && (rotation <= 30)) || (rotation >= 330)) { if (mClick) { if (mIsLand && !mClickLand) { return; } else { mClickPort = true; mClick = false; mIsLand = false; } } else { if (mIsLand) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); mIsLand = false; mClick = false; } } } // 設置橫屏 else if (((rotation >= 230) && (rotation <= 310))) { if (mClick) { if (!mIsLand && !mClickPort) { return; } else { mClickLand = true; mClick = false; mIsLand = true; } } else { if (!mIsLand) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mIsLand = true; mClick = false; } } } } }; mOrientationListener.enable(); }
3.設置按鈕點擊切換屏幕方向響應事件
mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mClick = true; if (!mIsLand) { if (onClickOrientationListener != null) { onClickOrientationListener.landscape(); } setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mIsLand = true; mClickLand = false; } else { if (onClickOrientationListener != null) { onClickOrientationListener.portrait(); } setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); mIsLand = false; mClickPort = false; } } });
4.上面用到一個接口OnClickOrientationListener,裏面包含兩個方法,分別用於用戶點擊切換橫屏/豎屏時的回調;
interface OnClickOrientationListener { public void landscape(); public void portrait(); }
代碼貼完了, 簡單說說思路,點擊的時候,直接切換屏幕方向,切換以後,須要當手機屏幕也旋轉到所切換的方向以後,才又開始監聽手機屏幕旋轉事件,這樣就實現了setRequestedOrientation以後仍然能夠經過旋轉手機切換屏幕的功能;
舉個例子:
-->手機當前是豎屏狀態,Activity也是豎屏狀態
-->用戶點擊切換按鈕
-->Activity切換爲橫屏,手機爲豎屏;此時經過設置flag,使OrientationListener監聽到豎屏時再也不處理事件,waiting...
-->直到當用戶把手機旋轉爲橫屏狀態以後,更改flag,使OrientationListener監聽到豎屏時處理相應的事件
-->當用戶再次旋轉手機切換爲豎屏以後,Activity便可自動切換爲豎屏;
橫屏點擊切換豎屏理論同上;
第三步,用戶點擊切換按鈕以後進入橫屏,此時就不響應監聽到的豎屏處理事件,而且要等待到第四步用戶把手機旋轉爲橫屏狀態以後再響應豎屏監聽;這樣定義彷佛不太合理,但從用戶的角度看,不可能用戶點擊了要進入橫屏,卻仍然把手機給豎屏方向拿着;
最後,當不須要監聽屏幕方向的時候,須要調用OrientationListener.disable()關閉監聽器;
小記錄一下相關知識01/07/2014
private int getScreenRotation() { WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); try { Method m = display.getClass().getDeclaredMethod("getRotation"); return (Integer) m.invoke(display); } catch (Exception e) { return Surface.ROTATION_0; } } private int getScreenOrientation() { switch (getScreenRotation()) { case Surface.ROTATION_0: return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; case Surface.ROTATION_90: return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; case Surface.ROTATION_180: return (Build.VERSION.SDK_INT >= 8 ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); case Surface.ROTATION_270: return (Build.VERSION.SDK_INT >= 8 ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); default: return 0; } }