Ref:http://blog.csdn.net/a_running_wolf/article/details/50477965
日常開發中我們經常會因為繪圖、繪制自定義組件、定位組件或者是計算布局高度需要減去狀態欄高度等需要來獲取Activity界面中狀態欄、標題欄的高度。但很多人馬上要拿起來就用還是會遇到各種各樣的問題,一時要查很多資料,很是不爽!今天也是猛然發現這個問題費了不少時間,終於有所收獲,特地記錄下來,希望給遇到同樣問題的你一點幫助,也給以后留個筆記。廢話少說,開始正題吧——
一、Activity界面區域划分
先上一張圖統一一下認識,有圖好說話:

簡單說明一下(上圖Activity采用默認Style,狀態欄和標題欄都會顯示):最大的草綠色區域是屏幕界面,紅色次大區域我們稱之為“應用界面區域”,最小紫色的區域我們稱之為“View繪制區域”;屏幕頂端、應用界面區之外的那部分顯示手機電池網絡運營商信息的為“狀態欄”,應用區域頂端、View繪制區外部顯示Activity名稱的部分我們稱為“標題欄”。
二、狀態高度的測量
(1)通過系統尺寸資源獲取
- /**
- * 獲取狀態欄高度——方法1
- * */
- int statusBarHeight1 = -1;
- //獲取status_bar_height資源的ID
- int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
- if (resourceId > 0) {
- //根據資源ID獲取響應的尺寸值
- statusBarHeight1 = getResources().getDimensionPixelSize(resourceId);
- }
- Log.e("WangJ", "狀態欄-方法1:" + statusBarHeight1);
- /**
- * 獲取狀態欄高度——方法2
- * */
- int statusBarHeight2 = -1;
- try {
- Class<?> clazz = Class.forName("com.android.internal.R$dimen");
- Object object = clazz.newInstance();
- int height = Integer.parseInt(clazz.getField("status_bar_height")
- .get(object).toString());
- statusBarHeight2 = getResources().getDimensionPixelSize(height);
- } catch (Exception e) {
- e.printStackTrace();
- }
- Log.e("WangJ", "狀態欄-方法2:" + statusBarHeight2);
- /**
- * 獲取狀態欄高度——方法3
- * 應用區的頂端位置即狀態欄的高度
- * *注意*該方法不能在初始化的時候用
- * */
- Rect rectangle= new Rect();
- getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle);
- //高度為rectangle.top-0仍為rectangle.top
- Log.e("WangJ", "狀態欄-方法3:" + rectangle.top);
(4)借助屏幕和應用區域高度
- /**
- * 獲取狀態欄高度——方法4
- * 狀態欄高度 = 屏幕高度 - 應用區高度
- * *注意*該方法不能在初始化的時候用
- * */
- //屏幕
- DisplayMetrics dm = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(dm);
- //應用區域
- Rect outRect1 = new Rect();
- getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1);
- int statusBar = dm.heightPixels - outRect1.height(); //狀態欄高度=屏幕高度-應用區域高度
- Log.e("WangJ", "狀態欄-方法4:" + statusBar);
有人看完會說,What Are You弄啥嘞,小學數學題!秀智商?——呵呵,是的!其實3、4這兩種方法其實本質是一樣,所以如果單單獲取statusBar高度而不獲取titleBar高度時也不推薦大家使用,理由同上方法3。
三、標題欄高度的測量
- //屏幕
- DisplayMetrics dm = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(dm);
- Log.e("WangJ", "屏幕高:" + dm.heightPixels);
- //應用區域
- Rect outRect1 = new Rect();
- getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1);
- Log.e("WangJ", "應用區頂部" + outRect1.top);
- Log.e("WangJ", "應用區高" + outRect1.height());
- //View繪制區域
- Rect outRect2 = new Rect();
- getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(outRect2);
- Log.e("WangJ", "View繪制區域頂部-錯誤方法:" + outRect2.top); //不能像上邊一樣由outRect2.top獲取,這種方式獲得的top是0,可能是bug吧
- int viewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); //要用這種方法
- Log.e("WangJ", "View繪制區域頂部-正確方法:" + viewTop);
- Log.e("WangJ", "View繪制區域高度:" + outRect2.height());
(1)top-top
- /**
- * 獲取標題欄高度-方法1
- * 標題欄高度 = View繪制區頂端位置 - 應用區頂端位置(也可以是狀態欄高度,獲取狀態欄高度方法3中說過了)
- * */
- int titleHeight1 = viewTop - outRect1.top;
- Log.e("WangJ", "標題欄高度-方法1:" + titleHeight1);
(2)高度-高度
- /**
- * 獲取標題欄高度-方法2
- * 標題欄高度 = 應用區高度 - View繪制區高度
- * */
- int titleHeight2 = outRect1.height() - outRect2.height();
- Log.e("WangJ", "標題欄高度-方法2:" + titleHeight2);
*注意*
(1)不管你是否設置全屏模式,或是不顯示標題欄,在使用獲取狀態欄高度方法1和獲取狀態欄高度方法2都會測量到狀態欄的高度,理解原理就不難解釋——系統資源屬性是固定的、真實的,不管你是否隱瞞(隱藏或者顯示),它都在那里;
(2)但是若使用獲取狀態欄高度方法3和獲取狀態欄高度方法4,以及獲取標題欄高度方法1和獲取標題欄高度方法2,都是依賴於WMS,是在界面構建后根據View獲取的,所以顯示了就有高度,不顯示自然沒高度了。
如果你沒時間驗證(或者是懶),我就勉為其難給你驗證一下吧:
先設置Activity全屏:
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen"
- android:screenOrientation="portrait" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
屏幕各區域獲取不變;
輸出StatusBar和titleBar高度信息:
- int titleHeight1 = viewTop - outRect1.top;
- Log.e("WangJ", "驗證Statue高度:" + titleHeight1);
- Log.e("WangJ", "驗證Title高度:" + outRect1.top);
看結果:

