為什么Android需要進(jìn)行屏幕適配
由于Android系統(tǒng)的開放性,任何用戶、開發(fā)者、OEM廠商、運(yùn)營商都可以對Android進(jìn)行定制,修改成他們想要的樣子。
但是這種“碎片化”到底到達(dá)什么程度呢?
在2012年,OpenSignalMaps(以下簡稱OSM)發(fā)布了第一份Android碎片化報(bào)告,統(tǒng)計(jì)數(shù)據(jù)表明,
2012年,支持Android的設(shè)備共有3997種。
2013年,支持Android的設(shè)備共有11868種。
2014年,支持Android的設(shè)備共有18796種。
下面這張圖片所顯示的內(nèi)容足以充分說明當(dāng)今Android系統(tǒng)碎片化問題的嚴(yán)重性,因?yàn)樵搱D片中的每一個矩形都代表著一種Android設(shè)備。
而隨著支持Android系統(tǒng)的設(shè)備(手機(jī)、平板、電視、手表)的增多,設(shè)備碎片化、品牌碎片化、系統(tǒng)碎片化、傳感器碎片化和屏幕碎片化的程度也在不斷地加深。而我們今天要探討的,則是對我們開發(fā)影響比較大的——屏幕的碎片化。
下面這張圖是Android屏幕尺寸的示意圖,在這張圖里面,藍(lán)色矩形的大小代表不同尺寸,顏色深淺則代表所占百分比的大小。
下圖是2014年初,友盟統(tǒng)計(jì)的占比5%以上的6個主流分辨率,可以看出,占比最高的是480800,320480的設(shè)備竟然也占據(jù)了很大比例,但是和半年前的數(shù)據(jù)相比較,中低分辨率(320480、480800)的比例在減少,而中高分辨率的比例則在不斷地增加。雖然每個分辨率所占的比例在變化,但是總的趨勢沒變,還是這六種,只是分辨率在不斷地提高。
所以說,我們只要盡量適配這幾種分辨率,就可以在大部分的手機(jī)上正常運(yùn)行了。
當(dāng)然了,這只是手機(jī)的適配,對于平板設(shè)備(電視也可以看做是平板),我們還需要一些其他的處理。
好了,到目前為止,我們已經(jīng)弄清楚了Android開發(fā)為什么要進(jìn)行適配,以及我們應(yīng)該適配哪些對象,接下來,終于進(jìn)入我們的正題了!
首先,我們先要學(xué)習(xí)幾個重要的概念。
屏幕尺寸: 也就是我們平時所說的某某手機(jī)是幾寸屏, 比如HTC one V這款手機(jī)是3.7寸的, 這里的寸說的是英寸(inch),國際上習(xí)慣使用的單位,3.7寸指的是屏幕的對角線的長度。
屏幕尺寸指屏幕的對角線的長度,單位是英寸,1英寸=2.54厘米
比如常見的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等 ```
**屏幕分辨率**: 指屏幕的寬和高的像素?cái)?shù), 比如HTC one V是480*800的。
屏幕分辨率是指在橫縱向上的像素點(diǎn)數(shù),單位是px,1px=1個像素點(diǎn)。一般以縱向像素橫向像素,如19601080。```
屏幕密度: 每inch的像素?cái)?shù),比如HTC one V, 是252 px/inch。
屏幕像素密度是指每英寸上的像素點(diǎn)數(shù),單位是dpi,即“dot per inch”的縮寫。屏幕像素密度與屏幕尺寸和屏幕分辨率有關(guān),在單一變化條件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。
dp、dip、dpi、sp、px
px我們應(yīng)該是比較熟悉的,前面的分辨率就是用的像素為單位,大多數(shù)情況下,比如UI設(shè)計(jì)、Android原生API都會以px作為統(tǒng)一的計(jì)量單位,像是獲取屏幕寬高等。
dip和dp是一個意思,都是Density Independent Pixels的縮寫,即密度無關(guān)像素,上面我們說過,dpi是屏幕像素密度,假如一英寸里面有160個像素,這個屏幕的像素密度就是160dpi,那么在這種情況下,dp和px如何換算呢?在Android中,規(guī)定以160dpi為基準(zhǔn),1dip=1px,如果密度是320dpi,則1dip=2px,以此類推。
假如同樣都是畫一條320px的線,在480*800分辨率手機(jī)上顯示為2/3屏幕寬度,在320*480的手機(jī)上則占滿了全屏,如果使用dp為單位,在這兩種分辨率下,160dp都顯示為屏幕一半的長度。這也是為什么在Android開發(fā)中,寫布局的時候要盡量使用dp而不是px的原因。
而sp,即scale-independent pixels,與dp類似,但是可以根據(jù)文字大小首選項(xiàng)進(jìn)行放縮,是設(shè)置字體大小的御用單位。
mdpi、hdpi、xdpi、xxdpi
其實(shí)之前還有個ldpi,但是隨著移動設(shè)備配置的不斷升級,這個像素密度的設(shè)備已經(jīng)很罕見了,所在現(xiàn)在適配時不需考慮。
mdpi、hdpi、xdpi、xxdpi用來修飾Android中的drawable文件夾及values文件夾,用來區(qū)分不同像素密度下的圖片和dimen值。```
那么如何區(qū)分呢?Google官方指定按照下列標(biāo)準(zhǔn)進(jìn)行區(qū)分:

在進(jìn)行開發(fā)的時候,我們需要把合適大小的圖片放在合適的文件夾里面。下面以圖標(biāo)設(shè)計(jì)為例進(jìn)行介紹。

在設(shè)計(jì)圖標(biāo)時,對于五種主流的像素密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)應(yīng)按照 2:3:4:6:8 的比例進(jìn)行縮放。例如,一個啟動圖標(biāo)的尺寸為48x48 dp,這表示在 MDPI 的屏幕上其實(shí)際尺寸應(yīng)為 48x48 px,在 HDPI 的屏幕上其實(shí)際大小是 MDPI 的 1.5 倍 (72x72 px),在 XDPI 的屏幕上其實(shí)際大小是 MDPI 的 2 倍 (96x96 px),依此類推。
雖然 Android 也支持低像素密度 (LDPI) 的屏幕,但無需為此費(fèi)神,系統(tǒng)會自動將 HDPI 尺寸的圖標(biāo)縮小到 1/2 進(jìn)行匹配。
下圖為圖標(biāo)的各個屏幕密度的對應(yīng)尺寸:

解決方案
支持各種屏幕尺寸
使用wrap_content、match_parent、weight
要確保布局的靈活性并適應(yīng)各種尺寸的屏幕,應(yīng)使用 “wrap_content” 和 “match_parent” 控制某些視圖組件的寬度和高度。
使用 “wrap_content”,系統(tǒng)就會將視圖的寬度或高度設(shè)置成所需的最小尺寸以適應(yīng)視圖中的內(nèi)容,而 “match_parent”(在低于 API 級別 8 的級別中稱為 “fill_parent”)則會展開組件以匹配其父視圖的尺寸。
如果使用 “wrap_content” 和 “match_parent” 尺寸值而不是硬編碼的尺寸,視圖就會相應(yīng)地僅使用自身所需的空間或展開以填滿可用空間。此方法可讓布局正確適應(yīng)各種屏幕尺寸和屏幕方向。
weight的計(jì)算方法
android:layout_weight的真實(shí)含義是:如果View設(shè)置了該屬性并且有效,那么該 View的寬度等于原有寬度(android:layout_width)加上剩余空間的占比。
使用相對布局,禁用絕對布局
在開發(fā)中,我們大部分時候使用的都是線性布局、相對布局和幀布局,絕對布局由于適配性極差,所以極少使用。
由于各種布局的特點(diǎn)不一樣,所以不能說哪個布局好用,到底應(yīng)該使用什么布局只能根據(jù)實(shí)際需求來確定。我們可以使用 LinearLayout 的嵌套實(shí)例并結(jié)合 “wrap_content” 和 “match_parent”,以便構(gòu)建相當(dāng)復(fù)雜的布局。不過,我們無法通過 LinearLayout 精確控制子視圖的特殊關(guān)系;系統(tǒng)會將 LinearLayout 中的視圖直接并排列出。
如果我們需要將子視圖排列出各種效果而不是一條直線,通常更合適的解決方法是使用 RelativeLayout,這樣就可以根據(jù)各組件之間的特殊關(guān)系指定布局了。
下面的代碼以官方Demo為例說明。

在上面的代碼中我們使用了相對布局,并且使用alignXXX等屬性指定了子控件的位置,下面是這種布局方式在應(yīng)對屏幕變化時的表現(xiàn)
在小尺寸屏幕的顯示

在平板的大尺寸上的顯示效果

雖然控件的大小由于屏幕尺寸的增加而發(fā)生了改變,但是我們可以看到,由于使用了相對布局,所以控件之前的位置關(guān)系并沒有發(fā)生什么變化,這說明我們的適配成功了。