術語和概念
螢幕尺寸
螢幕的物理尺寸,以螢幕的對角線長度作為依據(比如 2.8寸, 3.5寸)。
簡而言之, Android把所有的螢幕尺寸簡化為三大類:大,正常,和小。
程式可以針對這三種尺寸的螢幕提供三種不同的布局方案,然後系統會負責把你的布局方案以合適的方式渲染到對應的螢幕上,這個過程是不需要程式員用代碼來幹預的。
螢幕長寬比
螢幕的物理長度與物理寬度的比例。程式可以為制定長寬比的螢幕提供製定的素材,只需要用系統提供的資源分類符long和 notlong。
解析度
螢幕上擁有的像素的總數。注意,雖然大部分情況下解析度都被表示為“寬度×長度”,但解析度並不意味著螢幕長寬比。在 Android系統中,程式一般並不直接處理解析度。
密度
以螢幕解析度為基礎,沿螢幕長寬方向排列的像素。
密度較低的螢幕,在長和寬方向都只有比較少的像素,而高密度的螢幕通常則會有很多 ——甚至會非常非常多——像素排列在同一地區。螢幕的密度是非常重要的,舉個例子,長寬以像素為單位定義的介面元素(比如一個按鈕),在低密度的螢幕上會 顯得很大,但在高密度的螢幕上則會顯得很小。
密度無關的像素( DIP )
指一個抽象意義上的像素,程式用它來定義介面元素。它作為一個與實際密度無關的單位,協助程式員構建一個布局方案(介面元素的寬度,高度,位置)。
一個與密度無關的像素,在邏輯尺寸上,與一個位於像素密度為 160DPI的螢幕上的像素是一致的,這也是Android平台所假定的預設顯示裝置。在啟動並執行時候,平台會以目標螢幕的密度作為基準,“透明地”處理所 有需要的DIP縮放操作。要把密度無關像素轉換為螢幕像素,可以用這樣一個簡單的公式: pixels = dips * (density / 160)。舉個例子,在 DPI為 240的螢幕上, 1個 DIP等於 1.5個物理像素。我們強烈推薦你用 DIP來定義你程式的介面布局,因為這樣可以保證你的 UI在各種解析度的螢幕上都可以正常顯示。
為了簡化程式員面在對各種解析度時的困擾,也為了具備各種解析度的平台都可以直接運行這些程式, Android平台將所有的螢幕以密度和解析度為分類方式,各自分成了三類:
·三種主要的尺寸:大,正常,小;
·三種不同的密度:高( hdpi),中( mdpi)和低( ldpi)。 【DPI是“dot per inch”的縮寫,每英吋像素數。】
如果需要的話,程式可以為各種尺寸的螢幕提供不同的資源(主要是布局),也可以為 各種密度的螢幕提供不同的資源(主要是位元影像)。除此以外,程式不需要針對螢幕的尺寸或者密度作出任何額外的處理。在執行的時候,平台會根據螢幕本身的尺寸 與密度特性,自動載入對應的資源,並把它們從邏輯像素( DIP,用於定義介面布局)轉換成螢幕上的物理像素。
關於Android的nodpi,xhdpi,hdpi,mdpi,ldpi
首先是幾個基本概念:
1.螢幕尺寸Screen size
即顯示螢幕的實際大小,按照螢幕的對角線進行測量。
為簡單起見,Android把所有的螢幕大小分為四種尺寸:小,普通,大,超大(分別對應:small, normal, large, and extra large).
應用程式可以為這四種尺寸分別提供不同的自訂螢幕布局-平台將根據螢幕實際尺寸選擇對應布局進行渲染,這種選擇對於程式側是透明的。
2.螢幕長寬比Aspect ratio
長寬比是螢幕的物理寬度與物理高度的比例關係。應用程式可以通過使用限定的資源來為指定的長寬比提供螢幕布局資源。
3.螢幕解析度Resolution
在螢幕上顯示的物理像素總和。需要注意的是:儘管解析度通常用寬x高表示,但解析度並不意味著具體的螢幕長寬比。
在Andorid系統中,應用程式不直接使用解析度。
4.密度Density
根據像素解析度,在螢幕指定物理寬高範圍內能顯示的像素數量。
在同樣的寬高地區,低密度的顯示屏能顯示的像素較少,而高密度的顯示屏則能顯示更多的像素。
螢幕密度非常重要,因為其它條件不變的情況下,一共寬高固定的UI組件(比如一個按鈕)在在低密度的顯示屏上顯得很大, 而在高密度顯示屏上看起來就很小。
為簡單起見,Android把所有的螢幕解析度也分為四種尺寸:小,普通,大,超大(分別對應:small, normal, large, and extra large).
應用程式可以為這四種尺寸分別提供不同的資源-平台將透明的對資源進行縮放以適配指定的螢幕解析度。
5.裝置獨立像素Density-independent pixel (dp)
應用程式可以用來定義UI組件的虛擬像素單元,通過密度無關的方式來描述布局尺寸和位置。
一個裝置獨立像素相當於一個160 dpi螢幕上的物理像素。
在程式運行時,系統根據螢幕的實際密度透明的處理任何需要縮放的裝置獨立像素單元,裝置獨立像素轉換成螢幕實際像素的換算很簡單:pixels = dps * (density / 160).
例如在240 dpi的螢幕上,1個裝置獨立像素等於1.5物理像素.為確保UI組件在不同的螢幕都能合適的展示,強烈建議使用裝置獨立像素單元來定義你的應用程式UI。
四種螢幕尺寸分類:: small, normal, large, and xlarge
四種密度分類: ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)
需要注意的是: xhdpi是從 Android 2.2 (API Level 8)才開始增加的分類.
xlarge是從Android 2.3 (API Level 9)才開始增加的分類.
DPI是“dot per inch”的縮寫,每英吋像素數。
一般情況下的普通螢幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。
參考:http://developer.android.com/images/screens_support/screens-ranges.png
兩種擷取螢幕解析度資訊的方法:
DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
//這裡得到的像素值是裝置獨立像素dp
//DisplayMetrics metrics=activity.getResources().getDisplayMetrics(); 這樣獲得的參數資訊不正確,不要使用這種方式。
不能使用android.content.res.Resources.getSystem().getDisplayMetrics()。這個得到的寬和高是空的。
private void initResolutionStr(Context context) {
if (ApiConfig.getResolutionStr() == null || ApiConfig.getResolutionStr().equals("")) {
WindowManager winMgr = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display display = winMgr.getDefaultDisplay();
int height = display.getHeight();
int width = display.getWidth();
String resolution = height > width ? height + "x" + width : width + "x" + height;
ApiConfig.setResolutionStr(resolution);
// densityDpi = 120dpi is ldpi, densityDpi = 160dpi is mdpi,
// densityDpi = 240dpi is hdpi, densityDpi = 320dpi is xhdpi
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int densityDpi = dm.densityDpi;
ApiConfig.setDensityDpi(densityDpi);
}
}
如果需要為Android pad定製資源檔,則res目錄下的目錄可能為:
drawable
drawable-ldpi
drawable-mdpi
drawable-hdpi
drawable-xhdpi
drawable-nodpi
drawable-nodpi-1024×600
drawable-nodpi-1280×800
drawable-nodpi-800×480
values
values-ldpi
values-mdpi
values-hdpi
values-xhdpi
values-nodpi
values-nodpi-1024×600
values-nodpi-1280×800
values-nodpi-800×480
Android上常見度量單位:
px(像素):螢幕上的點,絕對長度,與硬體相關。
in(英寸):長度單位。
mm(毫米):長度單位。
pt(磅):1/72英寸,point。
dp(與密度無關的像素):一種基於螢幕密度的抽象單位。在每英寸160點的顯示器上,1dp = 1px。
dip:Density-independent pixel,同dp相同。
sp:在dp的基礎上,還與比例無關,個人理解為是一個向量圖形單位。
引入dp/dip的原因:
過去,程式員通常以像素為單位設計電腦使用者介面。例如,定義一個寬度為300像素的表單欄位,列之間的間距為5個像素,表徵圖大小為16×16像素 等。這樣處理的問題在於,如果在一個DPI(dpi)更高的新顯示器上運行該程式,則使用者介面會顯得很小。在有些情況下,使用者介面可能會小到難以看清 內容。與解析度無關的度量單位可以解決這一問題。
如何計算密度(請參照原帖:http://www.devdiv.com/thread-28610-1-1.html);
1.標準是240*320畫在1.5*2平方inch上。那麼像每平方英寸有240*320/(1.5*2)=25600點,也就是一平方英寸的像素點為25600,所以dpi取為它的平方根160;如果你的dpi是120,那麼它的密度就是0.75.
2.密度不只是與width有關,還與height有關,所以不管width是1.8還是1.3,它的密度都有可能是1;比如width是1.8,只要它 的height是3/1.8的話,如果pixel為240*320的話,它的密度仍舊是1;同樣如果width為1.3,只要它的 height為3/1.3的話,像素點為240*320,則密度也是1.
3.320*480/(1.5*2)得到單位平方英寸的點為51200,所以單位平方英寸是240*320畫在1.5*2螢幕的2倍。但是這是平方英寸啊,算密度的時候要開平方的啊,所以應該是2開平方,是1.414吧,大緻密度為1.5。
如何做到與密度無關:
如果螢幕密度為160,這時dp和sp和px是一樣的。1dp=1sp=1px,但如果使用px作單位,如果螢幕大小不變(假設還是3.2寸),而屏 幕密度變成了320。那麼原來TextView的寬度設成160px,在密度為320的3.2 寸螢幕裡看要比在密度為160的3.2寸螢幕上看短了一半。但如果設定成160dp或160sp的話。系統會自動將width屬性值設定成320px的。 也就是160 * 320 / 160。其中320 / 160可稱為密度比例因素。也就是說,如果使用dp和sp,系統會根據螢幕密度的變化自動進行轉換。官方文檔總結的計算公式為:pixels = dps * (density /160).
附:
傳說iPhone/Mac的設計從一開始就考慮到對任意解析度的支援,iOS的所有介面元素用的都已經是向量化了的圖片,UI介面是系統層級的與密度無關;而Android雖然支援任意解析度,但不是系統全域的,求證。