這幾天剛剛接觸了新的項目,做一個android用戶端。本周的工作是完成用戶端的UI介面和功能實現,但是對於Android開發最頭疼的部分,即是對於紛雜的螢幕做適配的工作現在來說是最棘手的!
映像顯示所需的概念:
像素:一幅圖片的顯示就是由許多顯示著不同顏色的小方格組成的,這樣的小方格就被稱為像素,是構成圖片的最小單位.但是這個像素的具體大小是多少呢?這需要取決於顯示這張圖片的具體的物理裝置顯示一個圖片像素點的熒光點的大小.圖片檔案只是記錄著它自身有多少個像素點,每個像素點顯示什麼顏色,至於它自身物理尺寸有多大,它自身也無法得知,例如一張480*800像素的圖片在電腦顯示器上顯示明顯要比在手機螢幕上顯示大很多,而這張圖片本身並沒有改變.只是手機的屏比電腦顯示器的屏要精細許多,也就是每一個物理像素點要小許多,密度也就大許多.
解析度:分為“映像解析度”與“物理顯示解析度”。它們都是水平像素點數與垂直像素點數的乘積,也就是像素總和數。映像解析度是指圖片檔案記錄著自身所有的像素數。物理顯示解析度是指物理顯示屏水平與垂直能顯示的像素數的乘積.有的人說解析度越高,顯示的圖片就越清晰,這點是針對物理尺寸相同的情況而言,因為一樣的解析度有可能尺寸可能不一樣大,這樣光就解析度來比較清晰度沒有可比性.
密度:就是物理裝置上單位尺寸裡的像素數,當然是密度越大圖片顯示就越清晰了.
Android系統的長度單位:
px:像素,終端上的一個物理像素點,例如,480*800的螢幕在橫向有320個象素,在縱向有480個象素。
dip(dp):與終端上的物理像素點無關,是一種基於螢幕密度抽象單位,被稱作“裝置獨立像素”,會隨著螢幕的密度進行自動的大小調整.
sp:比例像素,主要處理字型大小,可以根據使用者的字型大小喜好設定進行縮放.
in:英寸,標準長度單位
mm:毫米,標準長度單位
pt:磅,標準長度單位,1/72英寸
Android螢幕適配:
為什麼要適配:Android終端的物理尺寸,解析度的類別眾多,可能你為一種終端設計了一套UI符合要求,但是在另一類大小的物理終端上顯示就完全不是你想要的。
解決辦法:針對這種情況,Android提供了一套標準,它將螢幕分為三類,所以當你建立一個Android工程後,工程自動為你建立三個存放不同解析度,不同密度下的UI的檔案夾,如:
三個檔案夾下的UI對應不同解析度及密度的螢幕,對應關係如下:
|
螢幕類型 |
解析度 |
密度 |
尺寸 |
drawable-hdpi |
WVGA |
480*800 |
240 |
大 |
drawable-ldpi |
QVGA |
240*320 |
120 |
小 |
drawable-mdpi |
HVGA |
320*480 |
160 |
中 |
這三個檔案夾只是告訴Android你設計的UI是針對哪種螢幕解析度及密度進行設計的,Android終端會在開啟應用的時候自動根據終端類型去匹配與檔案夾裡提供的UI相近解析度及密度的圖片。
假設終端屏是WVGA類型的,也就是密度為240,那麼程式開啟時,會去提取drawable-hdpi檔案夾片,然後用一個物理像素去顯示一個圖片像素,因為你把圖片是放在drawable-hdpi檔案夾下的,也就是告訴Android你設計的UI是針對480*800,密度為240而言的,那麼它不會對圖片進行放大或縮小操作,正好用一個物理像素去顯示一個圖片像素。
當圖片的密度與螢幕密度相同,則不進行縮放.
當圖片的密度與螢幕密度不同,則進行縮放。
實驗1:
針對480*800的屏我設計了一張圖片(解析度是480*100),分別在不同物理解析度終端下進行顯示,看看Android會不會顯示不正常。圖片如下:
布局檔案:
<?xml version="1.0" encoding="utf-8"?> 2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 android:gravity="center" 7 > 8 9 <ImageView10 android:layout_width="wrap_content"11 android:layout_height="wrap_content"12 android:src="@drawable/density480800"/>13 14 </LinearLayout>
假設:這張圖片的寬是480像素,高為100像素,我將它放在drawable-hdpi檔案夾下,就是告訴Android我的設計意圖是針對480*800的Android終端而言的,那麼它會在480*800的終端上以一個物理像素去顯示一個圖片像素,如果將它放在解析度為240*320的終端上進行顯示,如果Android不對顯示進行處理的話,還是以一個物理像素去顯示一個圖片像素,終端必將顯示不下這張圖片,因為圖片像素超過了物理像素個數。
注意:我這裡只設計了一張圖片,並放置於drawable-hdpi檔案夾下,並沒有在其它檔案夾下放置相應的圖片,當Android進行匹配的時候也就只能匹配這張圖了。
結果:
WVGA屏:對比原圖,正好顯示下,大小相同
HVGA屏:對比原圖,能夠顯示下,對圖片進行了縮小操作.
QVGA屏:對比原圖,能夠顯示下,對圖片進行了縮小操作
實驗2:
針對240*320的屏我設計了一張圖片(解析度為:240*100),分別在不同物理解析度終端下進行顯示,看看Android會不會顯示不正常。圖片如下:
布局檔案:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/density240320"/> </LinearLayout>
這張圖就是專門為240*320的屏設計的,設計意圖就是圖片撐滿螢幕寬度,所以設定成wrap_content就夠了,沒有考慮其它屏的情況
假設:這張圖片的寬是240像素,高為100像素,我將它放在drawable-ldpi檔案夾下,就是告訴Android我的設計意圖是針對240*320密度為120的Android終端而言的,那麼它會在240*320的終端上以一個物理像素去顯示一個圖片像素,如果將它放在解析度為480*800的終端上進行顯示,如果Android不對顯示進行處理的話,還是以一個物理像素去顯示一個圖片像素,圖片必將偏離了設計意圖(設計本想這張圖片能夠充滿終端的螢幕),因為圖片像素小於物理像素個數。
QVGA屏:對比原圖,正好撐滿屏寬
HVGA屏:對比原圖,雖然設定成了wrap_content,但是Android還是對其進行了放大操作
WVGA:同上
總結:
1:只要對一種螢幕設計一套UI,Android總能通過放大或者縮小來適應螢幕來保證設計意圖,這個前提是布局裡的單位是dip
2:雖然Android總能夠很聰明地來保證你的設計意圖,但是實際工作中,最好還是要多設計幾套UI,因為像實驗2裡,放大後的圖片明顯要模糊了許多
3:如果考慮設計的工作量,只想設計一套UI,那最好也是針對大解析度的終端來設計,這樣圖片縮小比圖片放大的清晰度要好。
實驗3:
上面的圖片都是從drawable檔案夾裡擷取的,所以Android知道將圖片當成什麼密度來處理(放大或縮小),如果圖片是從data/data目錄或者sd卡上擷取的,Android會預設將圖片當作160的基準密度來處理,將實驗二的圖片放入data/data/cn.com/目錄下,並擷取設定到ImageView上,我們的本意是圖片充滿終端寬度,結果會是什麼樣呢?結果如下:
1 public class Test4Activity extends Activity { 2 private ImageView iv; 3 @Override 4 public void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.main); 7 8 iv = (ImageView)findViewById(R.id.image); 9 10 iv.setImageDrawable(new BitmapDrawable(BitmapFactory.decodeFile("data/data/cn.com/density-240-320.png")));11 12 }
HVGA屏下:
結果:圖片並沒有如願地充滿屏寬,原因就是Android將圖片的密度當作了160基準密度來處理,而終端屏密度又正好是160,密度相同圖片並不會進行縮放操作,所以終端會以一個物理像素來顯示一個圖片像素。所以寬240像素的圖片當然無法充滿寬320像素的屏。
處理:希望從非drawable目錄下擷取的圖片,Android也能協助我們進行智能地縮放,那就要告訴Android這張圖片採用什麼密度來處理。具體如下:
public class Test4Activity extends Activity { private ImageView iv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); iv = (ImageView)findViewById(R.id.image); BitmapFactory.Options options = new BitmapFactory.Options(); //設定工廠以120的密度來讀取圖片檔案 options.inDensity = 120; BitmapDrawable image = new BitmapDrawable(BitmapFactory.decodeFile("data/data/cn.com/density-240-320.png",options)); //設定圖片在終端中以終端本身的密度來顯示圖片 image.setTargetDensity(getApplicationContext().getResources().getDisplayMetrics()); iv.setImageDrawable(image);}
最終效果:
HVGA屏下:
結束:Android中長度單位最好使用與物理像素無關的邏輯像素dip,這樣Android就能協助我們自動適應不同的螢幕,保持設計意圖。
Android中圖片大小的轉換是基於密度,與螢幕解析度和尺寸大小無關.
原文地址:http://www.cnblogs.com/wujd/archive/2012/03/25/2417127.html