android之Display.getRotation()_感測器控制螢幕旋轉
在看android自帶的samples原始碼裡面的AccelerometerPlayActivity時,看到下面這段程式碼,很不理解
public void onSensorChanged(SensorEvent event) { if(event.sensor.getType() != Sensor.TYPE_ACCELEROMETER){ return; } switch (mDisplay.getRotation()) { case Surface.ROTATION_0://手機處於正常狀態 mSensorX = event.values[0]; mSensorY = event.values[1]; break; case Surface.ROTATION_90://手機旋轉90度 mSensorX = -event.values[1]; mSensorY = event.values[0]; break; case Surface.ROTATION_180: mSensorX = -event.values[0]; mSensorY = -event.values[1]; break; case Surface.ROTATION_270: mSensorX = event.values[1]; mSensorY = -event.values[0]; break; } }
經過查閱資料大體瞭解了
通過AndroidManifest.xml設定螢幕方向的話,安裝後就不能改變,而程式內部設定螢幕方向就不會有這個限制。主要靠這兩個API:getRequestedOrientation()和setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)這兩個API通過ActivityManagerService.java的轉換後,實際上都是呼叫的WindowManagerService的同名方法。
每個Activity在WindowManagerService端都有一個AppWindowToken做代表,而螢幕的方向資訊就儲存在這裡。
PhoneWindowManager會自動根據螢幕物理特性決定螢幕方向,看這段程式碼:
if (mPortraitRotation < 0) { // Initialize the rotation angles for each orientation once. Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); if (d.getWidth() > d.getHeight()) { mPortraitRotation = Surface.ROTATION_90; mLandscapeRotation = Surface.ROTATION_0; mUpsideDownRotation = Surface.ROTATION_270; mSeascapeRotation = Surface.ROTATION_180; } else { mPortraitRotation = Surface.ROTATION_0; mLandscapeRotation = Surface.ROTATION_90; mUpsideDownRotation = Surface.ROTATION_180; mSeascapeRotation = Surface.ROTATION_270; } }
這裡的d.getWidth() 和 d.getHeight()得到的是物理螢幕的寬高。一般來說,平板和手機的是不一樣的。
平板是寬比高大(0度時位於landscape模式,右轉90度進入porit模式),手機是高比寬大(0度是位於porit模式,右轉90度進入landscape模式)。如果應用程式只關心當前是橫屏還是豎屏,而不直接使用感測器的話,沒什麼問題。如果像依靠重力感應的遊戲那樣直接使用感測器,就需要自己根據物理螢幕的座標系對感測器資料做轉化,否則就會出現座標系混亂的問題。
如果沒有沒有通過上面的d.getWidth()和d.getHeight()來檢測裝置的物理螢幕從確定哪個是landscape和porit模式,而是直接假設裝置是和手機一樣的模式。由於遊戲執行在landscape模式下,它們都把感測器資料右轉90度。這樣做法在手機上是沒有問題,但在平板電腦上是不應該轉化的,這是因為物理螢幕寬比高大的情況下,預設就是landscape模式。
現在回到原始碼,在這裡沒有區分手機和平板,僅僅是用來轉換加速度的方向而已,也沒有必要區分.
case Surface.ROTATION_0://手機處於正常狀態
mSensorX = event.values[0];
mSensorY = event.values[1];
break;
這段就是如果手機的方向沒有旋轉,不管手機處於landscape還是porit模式,加速度的方向都不用變,而下面,如果手機旋轉了180度,說明x軸和y軸的方向完全反過來了,這時候對於加速度的方向就要調整到反向.還有90度和270度的情況都類似.
case Surface.ROTATION_180:
mSensorX = -event.values[0];
mSensorY = -event.values[1];
break;