Android開發筆記:屏幕適配


這幾天剛剛接觸了新的項目,做一個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的文件夾,如下圖:

drawable

三個文件夾下的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會不會顯示不正常。圖片如下:

density

布局文件:

<?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     <ImageView
10         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屏:對比原圖,正好顯示下,大小相同

image

 

HVGA屏:對比原圖,能夠顯示下,對圖片進行了縮小操作.

image

 

QVGA屏:對比原圖,能夠顯示下,對圖片進行了縮小操作

image

 

 

實驗2:

針對240*320的屏我設計了一張圖片(分辨率為:240*100),分別在不同物理分辨率終端下進行顯示,看看Android會不會顯示不正常。圖片如下:

density-240-320

 

布局文件:

<?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屏:對比原圖,正好撐滿屏寬

image

 

HVGA屏:對比原圖,雖然設置成了wrap_content,但是Android還是對其進行了放大操作

image

 

WVGA:同上

image

 

總結:

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屏下:

image

 

結果:圖片並沒有如願地充滿屏寬,原因就是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屏下:

image

 

結束:Android中長度單位最好使用與物理像素無關的邏輯像素dip,這樣Android就能幫助我們自動適應不同的屏幕,保持設計意圖。

Android中圖片大小的轉換是基於密度,與屏幕分辨率和尺寸大小無關.

 

原文地址:http://www.cnblogs.com/wujd/archive/2012/03/25/2417127.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM