Android 自適應不一樣分辨率屏幕

前幾天,面試的時候,有問道關於如何自適應不一樣分辨率屏幕的問題。當時也是隻知其一;不知其二,今天索性看了不少資料,好好的總結了下。java

    首先解釋幾個基本的概念:android

    in:表示英寸,是屏幕的物理尺寸。每英寸等於2.54釐米。例如,形容手機屏幕大小,常常說,3.2(英)寸、3.5(英)寸、4(英)寸就是指這個單位。這些尺寸是屏幕的對角線長度。若是手機的屏幕是3.2英寸,表示手機的屏幕(可視區域)對角線長度是3.2*2.54 = 8.128釐米。web

   px:表示屏幕實際的象素。例如,320*480的屏幕在橫向有320個象素,在縱向有480個象素。面試

   dip或dp(與密度無關的像素):這個和設備硬件有關,爲了支持WVGA、HVGA和QVGA推薦使用這個。一種基於屏幕密度的抽象單位。設置一些view的寬高能夠用這個,通常狀況下,在不一樣分辨率,都不會有縮放的感受。若是用px的話,320px佔滿HVGA的寬度,到WVGA上就只能佔一半不到的屏幕了,那必定不是你想要的。app

   sp: 除了與密度無關外,還與scale無關 主要處理字體的大小。 ide

   density:屏幕密度,每英寸有多少個像素顯示點,與分辨率是兩個概念oop

   


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-portlayout-land兩個目錄,裏面分別放置豎屏和橫屏兩種佈局文件,以適應對橫屏豎屏自動切換。

2.提供不一樣的屏幕密度和不一樣的位圖drawables

   根據廣義密度,低,中型, 高,特高去添加不一樣的位圖資源。好比,如需對密度爲low的屏幕提供合適的圖片,需新建文件夾drawable-ldpi/。應儘可能使用點9格式的圖片,圖片大小的肯定:low:medium:high:extra high比例爲3:4:6:8。舉例來講,對於中等密度(medium)的屏幕你的圖片像素大小爲48×48,那麼低密度(low)屏幕的圖片大小應爲36×36,高(high)的爲72×72extra high96×96

3關於系統怎麼動態的尋找替代資源?

   1.系統根據當前的屏幕大小和密度,而後動態的採用程序中提供特定的資源。

   2.若是沒有匹配的資源,系統會使用默認的資源進行縮放從而符合當前屏幕的資源,默認的資源是那些沒有標籤配置限定符。

   關於系統的資源配置的目錄Android系統支持多配置資源文件,咱們能夠追加新的資源目錄到你的Android項目中。命名規範:資源名字-限制符



最後:

在xml佈局文件中,咱們既能夠設置px,也能夠設置dp(或者dip)。通常狀況下,咱們都會選擇使用dp,這樣能夠保證不一樣屏幕分辨率的機器上佈局一致。可是在代碼中,如何處理呢?不少控件的方法中都只提供了設置px的方法,例如setPadding,並無提供設置dp的方法。這個時候,若是須要設置dp的話,就要將dp轉換成px了。

如下是一個應用類,方便進行px和dp之間的轉換。


[java]  view plain copy
<EMBED id=ZeroClipboardMovie_1 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=18 width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. import android.content.Context;  
  2.   
  3. public class DensityUtil {  
  4.   
  5.     /** 
  6.      * 根據手機的分辨率從 dp 的單位 轉成爲 px(像素) 
  7.      */  
  8.     public static int dip2px(Context context, float dpValue) {  
  9.         final float scale = context.getResources().getDisplayMetrics().density;  
  10.         return (int) (dpValue * scale + 0.5f);  
  11.     }  
  12.   
  13.     /** 
  14.      * 根據手機的分辨率從 px(像素) 的單位 轉成爲 dp 
  15.      */  
  16.     public static int px2dip(Context context, float pxValue) {  
  17.         final float scale = context.getResources().getDisplayMetrics().density;  
  18.         return (int) (pxValue / scale + 0.5f);  
  19.     }  
  20. }  
[java]  view plain copy
<EMBED id=ZeroClipboardMovie_2 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=18 width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. import android.content.Context;  
  2.   
  3. public class DensityUtil {  
  4.   
  5.     /** 
  6.      * 根據手機的分辨率從 dp 的單位 轉成爲 px(像素) 
  7.      */  
  8.     public static int dip2px(Context context, float dpValue) {  
  9.         final float scale = context.getResources().getDisplayMetrics().density;  
  10.         return (int) (dpValue * scale + 0.5f);  
  11.     }  
  12.   
  13.     /** 
  14.      * 根據手機的分辨率從 px(像素) 的單位 轉成爲 dp 
  15.      */  
  16.     public static int px2dip(Context context, float pxValue) {  
  17.         final float scale = context.getResources().getDisplayMetrics().density;  
  18.         return (int) (pxValue / scale + 0.5f);  
  19.     }  
  20. }
相關文章
相關標籤/搜索