1.概況
作為Android開發者,最頭疼的莫過於讓自己開發的程序在不同終端上面的顯示效果看起來盡量一致(當然,假設要充分利用大屏幕的優勢另當別論)。在全球范圍內來講。android有着數以億計的設備,當中就不乏設備分辨率多種多樣。以及設備屏幕物理尺寸的多樣化。
總得來說我們須要做的有三點。其一讓APP的每一個UI中的每一個View寬和高更加靈活以適應不同分辨率、其二對於大屏幕設備(PAD)須要有不同的設計,竟可能多的展示內容。獲取你整個APP的全部UI都能夠做到一個布局中來、其三圖標資源需提供不同尺寸(MDPI、HDPI、XHDPI、XXHDPI、XXXHDPI)。你也能夠圖方便僅僅提供一套較高尺寸的API,沒問題,這可能僅僅會使那些配置低的設備(或者說分辨率低。事實上實際這兩者普遍成正比)耗費很多其它的內存在載入資源圖片上面。
2.官方支持
官方建議APP中使用的圖標資源都需提供drawable-ldpi(眼下來看。已經沒有必要)、drawable-mdpi、drawable-hdpi、drawable-xhdpi。
說到DPI(Dots Per Inch)事實上就是單位尺寸有多少個像素,計算方式就是手機分辨率寬的平方+高的平方。再開根號得到斜對角線分辨率。然后用這個除以屏幕的實際尺寸(也就是我們常說的4寸、5寸、7寸、10寸),這個尺寸實際也是屏幕的斜對角尺寸。這樣計算出來的結果就是像素密度,像素密度越大說明手機顯示越細膩。舉個樣例HTC One分辨率是1920*1080,屏幕尺寸是4.7英寸,拿上面的公式計算一下2202/4.7=468那么它屬於上面哪個區域呢?android給出了一個范圍,例如以下:
非常顯然HTC One 被歸入xhdpi這一類里面。
所以假設你的APP提供了drawable-xhdpi以下的圖標。HTC One執行你APP時會自己選擇載入那里面的。
2.布局
Android的五大布局各自是LinearLayout(線性布局)、FrameLayout(幀布局)、RelativeLayout(相對布局)、AbsoluteLayout(絕對布局)和TableLayout(表格布局)。
當中用得最多的要數LinearLayout和RelativeLayout,FrameLayout和TableLayout可在有特效需求的頁面使用。這里就不介紹。而AbsoluteLayout已經被標記位Deprecated since API level 3,不建議再使用。
線性布局的特點是,里面的每一個view都是按順序擺放,要么是垂直要么是水平,誰聲明在前面誰顯示時就排在前面。
而相對布局位置不受排放順序的限制,能夠在xml中指定它位於哪個view的上方、下方、左邊或右邊。
做自適應最關鍵的地方就在布局上面,首先拿到需求后分析頁面採用何種布局結構才干更好的做到自適應,或者APP設計時就設計得比較簡單。而手機端軟件的設計規則也是越簡單越好用。在布局上盡量使用match_parent個wrap_content。絕對不要使用px(當然假設你的APK僅僅須要支持某一種分辨率除外),非要設置詳細大小時使用dp做單位。這樣才干在不同DPI但物理尺寸大小一樣的手機上面通用。
但都用dp並不能滿足同一時候適應手機和平板(物理尺寸存在較大差異),由於平板的物理尺寸比較大一般是7寸以上,舉個樣例。兩個Button將其大小設置為width 50dp height 50dp,它在800*480 尺寸為4寸的手機上面顯示效果例如以下:
而在1024*600的七寸平板上面顯示效果例如以下:
非常顯然在平板上面顯示效果感覺太小了,為什么會出現如此差異。我們能夠通過計算得出答案。
800*400 4寸 DPI是230,normal狀態下DPI是160,據此我們能夠算出50dp在這個800*480 4寸設備上面占用的像素是230/160*50 = 72px 。顯然這個寬度僅僅占到整個屏幕寬度的72/480=0.15,再看看截圖,應該差點兒相同是這么個比例吧。假設是在1024*600的7寸(DPI是170)設備上面50dp占用的像素是170/160*50=53px,這樣整個button占領屏幕的寬度就僅僅有53/600=0.09。也就是如截圖看到的一樣占用非常小的一坨。
所以。通過dp作為單位不能解決不同尺寸設備的自適應問題,相同android也提供了對應的解決的方法,在android3.2 (API 13)曾經對屏幕大小做了例如以下分類:
要想在布局文件里區分不同尺寸設備能夠通過layout-small、layout-normal、layout-large和layout-xlarge。依據我們剛才計算的值,僅僅需在layout-large中指定button的大小為x這個x的值能夠通過公式算出來x*(170/160)/600=0.15 x = 600*0.15/(170/160)=95dp,再看下效果例如以下:
這樣就它們顯示起來的效果就差點兒一樣了。同一時候,不光是大小,顯示的位置都能夠依據屏幕的大小做不同的顯示。普通情況下你須要維護layout layout-large和layout-xlarge三套布局文件。在android 3.2以后官方又提供了更加精確的尺寸大小區分辦法。sw<N>dp,當中sw指的是長和寬中的較小者,比方1024*600的7寸,sw的計算方式是600/(170/160)=565dp,但實際是不正確的,參考網頁《官方六》中的描寫敘述:
Note: The sizes that you specify using thesequalifiers are not the actual screen sizes. Rather, the sizes arefor the width or height in dp units that are available to youractivity's window. The Android system might use some of the screen forsystem UI (such as the system bar at the bottom of the screen or the status barat the top), so some of the screen might not be available for your layout.Thus, the sizes you declare should be specifically about the sizes needed byyour activity—the system accounts for any space used by system UI whendeclaring how much space it provides for your layout. Also beware thatthe Action Bar isconsidered a part of your application's window space, although your layout doesnot declare it, so it reduces the space available for your layout and you mustaccount for it in your design.
所以說須要注意的是計算sw時會有一定得區間浮動,我們須要盡量定義小些,比方565dp假設你定義為sw565dp。但實際是sw564dp,那么就不會走到sw565dp里面去了,而是採用向下找近期的原則,假設都沒找到就使用默認的layout。
對於官方為什么會引入sw這個概念。是由於large xlarge已經不能適應各種廠商太多的中間尺寸,比方5.5 、5.7、 6 、 6.5等等,假設是android3.2下面,這些將所有被歸入large的范疇,這種話5.5和7寸設備顯示的效果就會有些出入,當然不會有非常大出入。
為了滿足人們對設計的精益求精,在android3.2以后的設備中都能夠使用sw來做更細的划分。如sw480dp sw600dp sw720dw sw1024dp等等。
當然為了避免維護如此多的layout布局文件我們還能夠用另外的版本號來完畢自適應的動作。如上面的樣例,每一個button都是占屏幕寬度的0.15。我們能夠用layout_weight權重這一概念。設置該button的權重為0.15就可以,它就會在每一個設備上面達到相同的效果—均占屏幕寬度的0.15,高也是同理。
對與寬高比例一致的設備這是一個不錯的選擇。但對與不同寬高比的設備。全然使用layout_weight來做自適應顯然是不能達到效果的。比方800*480和854*480的設備,假設高採用相同的weight,854的高肯定會顯得拉伸。假設button上面有背景圖片,則圖片會變形。有一個小技巧能夠解決此問題。就是用ImageView來取代Button,同一時候將背景圖片設置為android:src。曾經景的模式顯示,這樣能夠利用imageview的屬性,使圖片保持原始的比例填充。
3.數值
布局文件里會用到各種數值,如view的寬、高,字體的大小padding大小。magin大小等均能夠在values目錄中定義當中就包含strings.xml dimens.xml styles.xmlcolor.xml等等,當然跟自適應相關的就是dimens.xml。這里面定義了各種view屬性的大小。比如button的高為50dp能夠在dimens里面定義<dimen name="btn_size">50dp</dimen>然后將button的android:layout_width="@dimen/btn_size "。在布局部分我們講到用layout-large layout-sw600dp等來區分不同屏幕大小的設備。相同在values里面也能夠加上values-largevalues-sw600dp等來區分,比方最開始的樣例里面我們能夠僅僅定義一個layout 將button的寬高都設置為@dimen/ btn_size,然后定義一個values/dimen.xml 和一個values-large/dimen.xml,分別寫上<dimen name="btn_size">50dp</dimen>和<dimen name="btn_size">95dp</dimen>。這和寫多個layout效果是一樣的。
但我個人認為假設頁面相對照較簡單,在values里面下功夫比寫多個layout要簡單些。
3. 擴展
有時我們APP須要支持到比較舊的API版本號,但我們有想用到一些比較高級的API里面的功能,這時我們能夠在values后面加上-v<xx>如values-v11。當中11就是API版本號,也就是11以上API的設備就會採用values-v11里面的內容。
就比方API 11里面增加了Action Bar的功能,那么假設你想利用這個特性。能夠在values-v11里面定義一個style.xml,繼承自action bar相關的style。而在values里面的style.xml中定義不支持action bar的style,但在布局中用其它view來模擬action bar的效果。
4.總結
對與UI自適應總結一下主要是兩點,同樣屏幕尺寸不同分辨率以及不同屏幕尺寸同樣分辨率。對於前者,僅僅需在布局中用到單位的地方所實用dp就可以解決(有條件的話drawable最好能提供不同分辨率icon。實在不行。提供同意范圍內盡量大分辨率圖片)。
對於后者。則須要依據尺寸的等級寫不同的layout文件或者values文件,這個需依據項目的詳細負責程度來自由選擇。