天天看點

Android 自适應不同分辨率螢幕

前幾天,面試的時候,有問道關于如何自适應不同分辨率螢幕的問題。當時也是一知半解,今天索性看了很多資料,好好的總結了下。

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

    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:螢幕密度,每英寸有多少個像素顯示點,與分辨率是兩個概念

Android 自适應不同分辨率螢幕

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項目中。命名規範:資源名字-限制符

Android 自适應不同分辨率螢幕

最後:

在xml布局檔案中,我們既可以設定px,也可以設定dp(或者dip)。一般情況下,我們都會選擇使用dp,這樣可以保證不同螢幕分辨率的機器上布局一 緻。但是在代碼中,如何處理呢?很多控件的方法中都隻提供了設定px的方法,例如setPadding,并沒有提供設定dp的方法。這個時候,如果需要設 置dp的話,就要将dp轉換成px了。

以下是一個應用類,友善進行px和dp之間的轉換。

[java] view plaincopy

  1. import android.content.Context;  
  2. public class DensityUtil {  
  3.     public static int dip2px(Context context, float dpValue) {  
  4.         final float scale = context.getResources().getDisplayMetrics().density;  
  5.         return (int) (dpValue * scale + 0.5f);  
  6.     }  
  7.     public static int px2dip(Context context, float pxValue) {  
  8.         final float scale = context.getResources().getDisplayMetrics().density;  
  9.         return (int) (pxValue / scale + 0.5f);  
  10.     }  
  11. }  

[java] view plaincopy

  1. import android.content.Context;  
  2. public class DensityUtil {  
  3.     public static int dip2px(Context context, float dpValue) {  
  4.         final float scale = context.getResources().getDisplayMetrics().density;  
  5.         return (int) (dpValue * scale + 0.5f);  
  6.     }  
  7.     public static int px2dip(Context context, float pxValue) {  
  8.         final float scale = context.getResources().getDisplayMetrics().density;  
  9.         return (int) (pxValue / scale + 0.5f);  
  10.     }  
  11. }  

轉載于:https://my.oschina.net/u/1780920/blog/402346