前幾天,面試的時候,有問道關于如何自适應不同分辨率螢幕的問題。當時也是一知半解,今天索性看了很多資料,好好的總結了下。
首先解釋幾個基本的概念:
in:表示英寸,是螢幕的實體尺寸。每英寸等于2.54厘米。例如,形容手機螢幕大小,經常說,3.2(英)寸、3.5(英)寸、4(英)寸就是指這個單 位。這些尺寸是螢幕的對角線長度。如果手機的螢幕是3.2英寸,表示手機的螢幕(可視區域)對角線長度是3.2*2.54 = 8.128厘米。
px:表示螢幕實際的象素。例如,320*480的螢幕在橫向有320個象素,在縱向有480個象素。
dip或dp(與密度無關的像素):這個和裝置硬體有關,為了支援WVGA、HVGA和QVGA推薦使用這個。一種基于螢幕密度的抽象機關。設定一些 view的寬高可以用這個,一般情況下,在不同分辨率,都不會有縮放的感覺。如果用px的話,320px占滿HVGA的寬度,到WVGA上就隻能占一半不 到的螢幕了,那一定不是你想要的。
sp: 除了與密度無關外,還與scale無關 主要處理字型的大小。
density:螢幕密度,每英寸有多少個像素顯示點,與分辨率是兩個概念
VGA:480*640
Low:120 Medium:240 High:480
友善記憶的法子:QVGA即"Quarter VGA"。顧名思義即VGA的四分之一尺寸
HVGA 即“Half VGA”
WVGA即VGA的另一種形式,比VGA分辨率高,别名 : Wide VGA, ,其分辯率為800×480象素。是擴大了VGA(640×480)的分辨率。應用于PDA和手機等,因為很多網頁的寬度都是800,是以WVGA的螢幕 會更加适和于浏覽網頁,可以說是未來手持裝置的分辨率的大趨勢
換算公式:px=(density/160)dp其中density一般為3個常用固定值240/160/120
比如如果在螢幕為320*480設定一個view的大小為320px,則這個view充滿整個width,如果裝置螢幕為480*800,則這個view 隻是充滿width的320/480=2/3。顯然不符合自适應不同的分辨率要求。如果設定view的大小為320dp,則根據px = (density/160)dp,480*800的螢幕密度為240,可知px=1.5dp。是以真實像素大小為320*1.5=480
然後我在模拟器上測試了下,但發現一個問題,列印出來的并非是模拟器的真實分辨率,又查了下,成功解決
在一個Activity的onCreate方法中,寫入如下代碼:
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 螢幕寬度(像素)
int height = metric.heightPixels; // 螢幕高度(像素)
float density = metric.density; // 螢幕密度(0.75 / 1.0 / 1.5)
int densityDpi = metric.densityDpi; // 螢幕密度DPI(120 / 160 / 240)
但是,需要注意的 是,在一個低密度的小屏手機上,僅靠上面的代碼是不能擷取正确的尺寸的。比如說,一部240x320像素的低密度手機,如果運作上述代碼,擷取到的螢幕尺 寸是320x427。是以,研究之後發現,若沒有設定多分辨率支援的話,Android系統會将240x320的低密度(120)尺寸轉換為中等密度 (160)對應的尺寸,這樣的話就大大影響了程式的編碼。是以,需要在工程的AndroidManifest.xml檔案 中,<manifest>中加入supports-screens節點,具體的内容如下:
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:resizeable="true"
android:anyDensity="true" />
這樣的話,目前的Android程式就支援了多種分辨率,那麼就可以得到正确的實體尺寸了。
如此測試通過沒問題!
另一方面:預設情況下面系統會自動調整和縮放位圖,但是難免拉伸位圖
apk的資源包中,當螢幕density=240時使用hdpi标簽的資源
當螢幕density=160時,使用mdpi标簽的資源
當螢幕density=120時,使用ldpi标簽的資源。
不加任何标簽的資源是各種分辨率情況下共用的
1在XML布局,使用wrap_content和fill_parent來填充整個父視窗;
2使用FrameLayout的,而不是AbsoluteLayout,減少界面布局對螢幕大小的依賴;
3 NEVER usehard-coding for pixel value, use dip (density independent pixel)(不要寫死像素值px,而是使用獨立像素值的dip)
4根據density和resolution 為不同的裝置準備合适的圖檔資源。
具體方案:
1.根據不同螢幕尺寸,提供不同布局
為了保證你的位圖是最好看的,預設情況下面,android會自動調整應用程式的布局,但是大多數情況下面,根據廣義尺寸,小,正常,大,更大去增加不同的布局資源。比如,如果需要對大小為large的螢幕提供支援,需要在res目錄下建立一個檔案夾layout-large/并提供layout。當然,也可以在res目錄下建立layout-port和layout-land兩個目錄,裡面分别放置豎屏和橫屏兩種布局檔案,以适應對橫屏豎屏自動切換。
2.提供不同的螢幕密度和不同的位圖drawables
根據廣義密度,低,中型, 高,特高去添加不同的位圖資源。比如,如需對密度為low的螢幕提供合适的圖檔,需建立檔案夾drawable-ldpi/。應盡量使用點9格式的圖檔,圖檔大小的确定:low:medium:high:extra high比例為3:4:6:8。舉例來說,對于中等密度(medium)的螢幕你的圖檔像素大小為48×48,那麼低密度(low)螢幕的圖檔大小應為36×36,高(high)的為72×72,extra high為96×96。
3關于系統怎麼動态的尋找替代資源?
1.系統根據目前的螢幕大小和密度,然後動态的采用程式中提供特定的資源。
2.如果沒有比對的資源,系統會使用預設的資源進行縮放進而符合目前螢幕的資源,“預設”的資源是那些沒有标簽配置限定符。
關于系統的資源配置的目錄(Android系統支援多配置資源檔案,我們可以追加新的資源目錄到你的Android項目中。命名規範:資源名字-限制符
最後:
在xml布局檔案中,我們既可以設定px,也可以設定dp(或者dip)。一般情況下,我們都會選擇使用dp,這樣可以保證不同螢幕分辨率的機器上布局一 緻。但是在代碼中,如何處理呢?很多控件的方法中都隻提供了設定px的方法,例如setPadding,并沒有提供設定dp的方法。這個時候,如果需要設 置dp的話,就要将dp轉換成px了。
以下是一個應用類,友善進行px和dp之間的轉換。
[java] view plaincopy
- import android.content.Context;
- public class DensityUtil {
- public static int dip2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
- public static int px2dip(Context context, float pxValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (pxValue / scale + 0.5f);
- }
- }
[java] view plaincopy
- import android.content.Context;
- public class DensityUtil {
- public static int dip2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
- public static int px2dip(Context context, float pxValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (pxValue / scale + 0.5f);
- }
- }
轉載于:https://my.oschina.net/u/1780920/blog/402346