本文記錄一些適配問(wèn)題的研究此叠,基礎(chǔ)概念不做過(guò)多介紹杖狼。
Android在做屏幕適配的時(shí)候一般考慮兩個(gè)因素:分辨率和dpi醋奠。分辨率是屏幕在橫向莫换、縱向上的像素點(diǎn)數(shù)總和,一般用“寬x高”的形式表示响蕴,例如:1080x1920谆焊。dpi是dots per ich的縮寫,表示每英寸的像素點(diǎn)數(shù)浦夷,例如160dpi指手機(jī)水平或垂直方向上每英寸距離有160個(gè)像素點(diǎn)辖试。
一、dp和px
dp和px都是編寫布局時(shí)的單位劈狐,它們之間可以通過(guò)dpi來(lái)?yè)Q算罐孝,換算公式如下:
- 公式一:px值 = dp值 * (dpi/160)
常見(jiàn)的還有一個(gè)density的概念,表示基準(zhǔn)比例肥缔,density = (dpi/160)莲兢,所以還有如下公式:
- 公式二:px值 = dp值 * density
注:公式中的160是android中規(guī)定的基準(zhǔn),即:在160dpi的屏幕上续膳,1dp=1px
通過(guò)上面的公式理解dp的概念
dp和dip的含義相同改艇,都是density-independent pixel的縮寫,表示密度無(wú)關(guān)像素坟岔,可以保證在不同像素密度的屏幕上顯示相同的效果谒兄。舉個(gè)例子:
兩種常見(jiàn)的屏幕參數(shù)如下:
- 屏幕1:分辨率=720x1280,dpi=320
- 屏幕2:分辨率=1080x1920社付,dpi=480
如果要實(shí)現(xiàn)一個(gè)view的寬度占屏幕1寬度的一半承疲,由分辨率可知需要view的寬度是360px,根據(jù)公式一可以知道使用180dp可以實(shí)現(xiàn)相同的效果(360 = dp值 * (320/160) -> dp值=180)瘦穆。
接下來(lái)再根據(jù)公式一纪隙,看看180dp在屏幕2上的顯示效果,px值 = 180 * (480/160) = 540扛或,正好是屏幕2寬度的一半绵咱。所以,使用180dp就可以同時(shí)在兩個(gè)屏幕上顯示相同的效果了熙兔。
二悲伶、實(shí)際工作中如何使用dp適配
實(shí)際工作中,我們一般會(huì)使用限定符建立多個(gè)資源文件來(lái)做適配住涉,一般會(huì)適配mdpi麸锉,hdpi,xhdpi舆声,xxhdpi等花沉,比如res下的values資源目錄如下:
- res/values-mdpi
- res/values-hdpi
- res/values-xhdpi
然后在不同的目錄下定義不同的dp值柳爽。上面180dp的例子說(shuō)明了dp值已經(jīng)保證了在不同像素密度的屏幕上顯示相同的效果,那么為什么還要針對(duì)不同的屏幕定義不同的dp值碱屁?不同的dp值如何確定的磷脯?下面結(jié)合例子解釋這兩個(gè)問(wèn)題。
1. 為什么要針對(duì)不同的屏幕定義不同的dp值娩脾?
這是因?yàn)閍ndroid機(jī)型屏幕尺寸太碎片化了赵誓,一個(gè)dp值并不能滿足所有機(jī)型,比如常見(jiàn)的還有如下這種:
- 屏幕3:分辨率=480x800柿赊,dpi=240
通過(guò)前面的公式計(jì)算可以知道俩功,前面例子的180dp在這個(gè)屏幕上并不是寬度的一半,160dp才是一半碰声。由此可見(jiàn)诡蜓,一個(gè)dp值并不能滿足所有屏幕,所以需要使用限定符適配不同的dpi奥邮。最終適配這三種屏幕如下:
- res/values-hdpi/dimens.xml 中定義資源160dp 適配屏幕3
- res/values-xhdpi/dimens.xml 中定義資源180dp 適配屏幕1
- res/values-xxhdpi/dimens.xml 中定義資源180dp 適配屏幕2
限定符mdpi万牺,hdpi,xhdpi等與dpi的對(duì)應(yīng)關(guān)系后面給出
2. 不同限定符下的dp值如何確定的洽腺?
比如現(xiàn)在項(xiàng)目中有了一套屏幕1(xhdpi)的資源res/values-xhdpi/dimens.xml
,其中有一個(gè)資源值是90dp覆旱,如果要求再適配一下屏幕3(hdpi)蘸朋,那么res/values-hdpi/dimens.xml中與90dp同名的資源應(yīng)該是多少dp呢?通過(guò)前面的介紹扣唱,這個(gè)值是很好計(jì)算的:
- 根據(jù)公式一計(jì)算90dp在屏幕1上是多少px
px = 90 * (320/160) = 180 - 根據(jù)1中計(jì)算出的像素藕坯,計(jì)算在屏幕3下同樣比例的像素?cái)?shù)
屏幕3下的px = 480 * (180/720) = 120 - 根據(jù)上一步的結(jié)果和公式一計(jì)算出在屏幕3的dp值
dp = 80
如果把計(jì)算過(guò)程中的90dp改成任意值r,那么最終噪沙,屏幕1的每一個(gè)資源值 r 乘以 8/9 就是在屏幕3下的dp值炼彪,對(duì)應(yīng)的資源文件就是:
- res/values-xhdpi/dimens.xml 中定義資源 r dp (適配屏幕1)
- res/values-hdpi/dimens.xml 中定義資源 r*8/9 dp (適配屏幕3)
這里計(jì)算出來(lái)的8/9是使用橫向分辨率和dpi計(jì)算出來(lái)的,如果是縱向的話并不是這個(gè)比例正歼,所以適配的時(shí)候需要區(qū)分橫豎向不同的比例轉(zhuǎn)換辐马。比如寬、橫向邊距等使用橫向的比例局义,高喜爷、豎直邊距等使用豎向比例。
需要注意的是這里是按比例計(jì)算出來(lái)的萄唇,最終的值還得根據(jù)實(shí)際情況和顯示效果而定。因?yàn)椴灰欢ㄋ薪缑娴脑O(shè)計(jì)都是按比例適配的另萤;還有就是有些帶虛擬按鍵的1080x1920的手機(jī),真實(shí)的豎直像素?cái)?shù)應(yīng)該是1920減去虛擬按鍵的高度;還有一點(diǎn)泛源,在android開(kāi)發(fā)中所說(shuō)的dpi的值并不是物理定義的拔妥,而是系統(tǒng)文件寫進(jìn)去的,所以這個(gè)值是可以被修改的俩由。另一層意思是毒嫡,dpi并不是由分辨率和屏幕尺寸計(jì)算出來(lái)的固定值。比如當(dāng)前常見(jiàn)的一種機(jī)型分辨率是1080x1920幻梯,尺寸是5.15英寸兜畸,dpi是480。按照dpi的定義碘梢,使用這個(gè)分辨率和尺寸計(jì)算dpi的話咬摇,結(jié)果并不是480。所以對(duì)分辨率和尺寸都相同的手機(jī)煞躬,dpi值不一定相同肛鹏,完全看手機(jī)廠商如何定義。不過(guò)恩沛,為了使顯示效果最好在扰,一般比較標(biāo)準(zhǔn)的手機(jī)dpi和分辨率都和下表一致:
ldpi | mdpi | hdpi | xhdpi | xxhdpi | |
---|---|---|---|---|---|
分辨率 | 240x320 | 320x480 | 480x800 | 720x1280 | 1080x1920 |
dpi | 120 | 160 | 240 | 320 | 480 |
所以,不同限定符下的dp值雷客,使用上面1,2,3步的計(jì)算方法能滿足大部分主流機(jī)型芒珠,但不一定能完美適配所有機(jī)型。
限定符與dpi的具體對(duì)應(yīng)關(guān)系如下:
限定符 | ldpi | mdpi | hdpi | xhdpi | xxhdpi |
---|---|---|---|---|---|
dpi | dpi<=120 | 120<dpi<=160 | 160<dpi<=240 | 240<dpi<=320 | 320<dpi<=480 |
限定符的知識(shí)不僅如此搅裙,這里不做過(guò)多介紹皱卓。
三、DisplayMetrics類和wm命令
代碼中部逮,可以通過(guò)DisplayMetrics類來(lái)獲取屏幕的一些信息娜汁,有三種方式可以獲取DisplayMetrics的實(shí)例:
//方法1
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
//方法2
WindowManager wm = (WindowManager) getSystemService(
Context.WINDOW_SERVICE);
DisplayMetrics metrics= new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
//方法3
DisplayMetrics metrics = getResources().getDisplayMetrics();
可以通過(guò)DisplayMetrics獲取的如下信息:
//等號(hào)后面的數(shù)值是某個(gè)手機(jī)的參數(shù),分辨率=1080x1920兄朋,dpi=480掐禁,尺寸5.15英寸
metrics.heightPixels = 1920
metrics.widthPixels = 1080
metrics.densityDpi = 480 //dpi值
metrics.density = 3.0 //基準(zhǔn)比例,dpi/160
metrics.xdpi = 422.03 //x方向準(zhǔn)確的物理像素密度
metrics.ydpi = 424.069 //y方向準(zhǔn)確的物理像素密度
metrics.scaledDensity = 3.0
這里的xdpi和ydpi和densityDpi的值不同蜈漓,再次說(shuō)明android開(kāi)發(fā)中所說(shuō)的dpi的值不是由硬件決定的穆桂。
利用DisplayMetrics類,可以實(shí)現(xiàn)一些常用的工具方法融虽,比如dp轉(zhuǎn)px,px轉(zhuǎn)dp等有额。或者在一些不方便使用資源適配的情況下茴迁,可以通過(guò)這個(gè)類判斷不同的dpi來(lái)通過(guò)java代碼來(lái)適配。
wm命令
wm命令是高通平臺(tái)下對(duì)手機(jī)分辨率猜旬、像素密度等進(jìn)行設(shè)置的命令倦卖。用法很簡(jiǎn)單:
首先使用adb shell命令進(jìn)入手機(jī)的shell中,然后就可以使用wm命令了熟嫩,常用的命令如下:
wm size //輸出手機(jī)的分辨率信息
如果要修改手機(jī)分辨率掸茅,上面的命令加上分辨率參數(shù)即可昧狮,比如把手機(jī)分辨率修改為800x1280陵且,命令如下
wm size 800x1280
如果要把上面命令修改的分辨率還原為手機(jī)原始的分辨率,使用下面的命令
wm size reset
上面是分辨率相關(guān)的命令茬底,dpi的命令和上面的類似获洲,如下:
wm density
wm density 240
wm density reset
掌握wm命令后贡珊,就可以方便的查看手機(jī)分辨率和dpi了门岔,也可以使用同一部手機(jī)測(cè)試多種分辨率的適配寒随。
注:使用wm命令修改分辨率或dpi后帮坚,在某些手機(jī)中试和,再使用reset命令還原后阅悍,手機(jī)某些內(nèi)容可能會(huì)顯示不正常(比如狀態(tài)欄昨稼、輸入法等)悦昵,重啟手機(jī)即可解決。
四寡痰、小結(jié)
通過(guò)前面幾節(jié)拦坠,應(yīng)該知道以下幾點(diǎn):
- 屏幕適配的時(shí)候一般考慮的兩個(gè)因素:分辨率和dpi贞滨。
- 利用dpi換算dp和px的值(兩個(gè)公式)
- 使用限定符適配不同dpi的屏幕拍棕,不同限定符下dp值的計(jì)算
- android開(kāi)發(fā)中使用的dpi的值是不固定的绰播,可以修改的
- 獲取手機(jī)屏幕信息的DisplayMetrics類和修改屏幕參數(shù)的wm命令
五蠢箩、drawable下的圖片適配
這里介紹drawable下的圖片資源的讀取和縮放的規(guī)則,也可以這樣說(shuō)滔韵,如何使用一套圖片資源適配多種dpi陪蜻。郭神的一篇博客 Android drawable微技巧囱皿,你所不知道的drawable的那些細(xì)節(jié)講的很清晰,這里取其精華做一個(gè)總結(jié)耕渴。
圖片資源的讀取規(guī)則
當(dāng)我們使用資源id來(lái)去引用一張圖片時(shí)橱脸,Android會(huì)使用一些規(guī)則來(lái)幫我們匹配最適合的圖片添诉。什么叫最適合的圖片医寿?比如我的手機(jī)屏幕密度是xxhdpi靖秩,那么drawable-xxhdpi文件夾下的圖片就是最適合的圖片沟突。因此惠拭,當(dāng)我引用一張圖片時(shí),如果drawable-xxhdpi文件夾下有這張圖就會(huì)優(yōu)先被使用棒呛,在這種情況下条霜,圖片是不會(huì)被縮放的。但是蒲凶,如果drawable-xxhdpi文件夾下沒(méi)有這張圖時(shí)旋圆, 系統(tǒng)就會(huì)自動(dòng)去其它文件夾下找這張圖了,優(yōu)先會(huì)去更高密度的文件夾下找這張圖片搀矫,也就是drawable-xxxhdpi文件夾,然后發(fā)現(xiàn)這里也沒(méi)有android_logo這張圖融欧,接下來(lái)會(huì)嘗試再找更高密度的文件夾噪馏,發(fā)現(xiàn)沒(méi)有更高密度的了欠肾,這個(gè)時(shí)候會(huì)去drawable-nodpi文件夾找這張圖拟赊,發(fā)現(xiàn)也沒(méi)有吸祟,那么就會(huì)去更低密度的文件夾下面找封豪,依次是drawable-xhdpi -> drawable-hdpi -> drawable-mdpi -> drawable-ldpi炒瘟。
android項(xiàng)目資源下的drawable(不帶任何限定符)目錄默認(rèn)就是drawable-mdpi的意思
作者:郭霖
鏈接:http://blog.csdn.net/guolin_blog/article/details/50727753
圖片資源的縮放規(guī)則
根據(jù)上面的讀取規(guī)則缘琅,如果最終沒(méi)有讀取到最適合的圖片廓推,而是讀取了低密度或高密度的圖片樊展,那么系統(tǒng)會(huì)自動(dòng)做一個(gè)縮放操作(低密度的圖片放大雷酪,高密度的圖片縮懈缌Α)。具體的縮放比例就是dpi的比例:
ldpi | mdpi | hdpi | xhdpi | xxhdpi | |
---|---|---|---|---|---|
dpi | 120 | 160 | 240 | 320 | 480 |
比例 | 3 | 4 | 6 | 8 | 12 |
比如當(dāng)前手機(jī)dpi是160(對(duì)應(yīng)mdpi)
如果讀取了drawable-mdpi下的圖片大小是48x48寞射,那么顯示到屏幕上的圖片大小是48x48(最適合的圖片不縮放)
如果讀取了drawable-ldpi下的圖片大小是48x48桥温,那么顯示到屏幕上的圖片大小是36x36(48/36 = 4/3)
如果讀取的是drawable-xhdpi下的圖大小是48x48策治,那么顯示到屏幕上的圖片大小是96x96通惫。
一套圖片資源適配多種dpi
根據(jù)Android的開(kāi)發(fā)建議履腋,我們?cè)跍?zhǔn)備圖片資源時(shí)盡量應(yīng)該給每種密度的設(shè)備都準(zhǔn)備一套遵湖,這樣程序的適配性就可以達(dá)到最好晚吞,比如AndroidStudio中新建項(xiàng)目的時(shí)候槽地,AS會(huì)默認(rèn)給我們生成不同規(guī)格的ic_launcher.png作為默認(rèn)的app圖標(biāo)捌蚊,如下:
- mipmap-mdpi/ic_launcher.png (48x48)
- mipmap-hdpi/ic_launcher.png (72x72)
- mipmap-xhdpi/ic_launcher.png (96x96)
- mipmap-xxhdpi/ic_launcher.png (144x144)
括號(hào)中是圖片大小缅糟,mipmap看成drawable即可。
上面的4個(gè)資源窗宦,通過(guò)計(jì)算可知赦颇,完全符合前面的圖片資源的縮放規(guī)則的比例關(guān)系,所以赴涵,上面的資源只保留一個(gè)的話同樣可以適配另外3種dpi沐扳。
類似的,項(xiàng)目中句占,UI設(shè)計(jì)師只需要給我們提供一種dpi下的一套圖片即可適配所有dpi,原理就是圖片資源的讀取縮放規(guī)則躯嫉。那么纱烘,我們希望UI給我們哪種dpi的圖片呢杨拐?當(dāng)然是高dpi下的圖片了,因?yàn)楦遜pi目錄下的圖片擂啥,顯示到低dpi的設(shè)備下,由縮放規(guī)則可以知道圖片會(huì)被縮小至扰。相反的绷杜,低dpi圖片顯示到高dpi的設(shè)備上齿诉,圖片會(huì)被放大。圖片縮小幾乎沒(méi)有什么副作用,而放大可能會(huì)影響圖片質(zhì)量,所以,使用高dpi目錄下的圖片適配效果更好,比如ic_launcher.png只保留一個(gè)的話浸遗,選擇保留 mipmap-xxhdpi/ic_launcher.png (144x144)髓帽。當(dāng)然译秦,也不是越高越好稍途,比如當(dāng)前手機(jī)市場(chǎng)有更高密度的手機(jī)xxxhdpi,但那是極少數(shù)甲馋,為了這極少數(shù)增加軟件包的大小是不劃算的痊远。當(dāng)然如果以后xxxhdpi的手機(jī)普及了逞姿,針對(duì)這種級(jí)別的屏幕密度來(lái)設(shè)計(jì)圖片就是首選了。
其他問(wèn)題
- 內(nèi)存方面蝴光,使用xxhdpi規(guī)格的圖片適配和使用mdpi規(guī)格的圖片適配,理論上它們對(duì)內(nèi)存的占用最終是相同的径簿。比如上面ic_launcher.png的例子,如果選擇使用mdpi適配,那么原圖大小是48x48,顯示到xxhdpi設(shè)備上之后激率,圖片被放大到144x144嘉冒。如果使用xxhdpi適配,那么原圖大小就是144x144银觅,顯示到xxhdpi設(shè)備上不會(huì)縮放洒忧,所以兩種適配方法减余,最終顯示到xxhdpi設(shè)備上的大小是一樣的,占用內(nèi)存也一樣惠勒。
- 需要注意的是,使用一套圖片做適配,在某些情況下可能會(huì)有一些問(wèn)題盾计,看:Android 開(kāi)發(fā)中 drawable 有必要放多套分辨率的圖片資源嗎?
- wm命令對(duì)于測(cè)試圖片并不好用,比如480dpi(對(duì)應(yīng)xxhdpi)的手機(jī)妥畏,如果使用wm命令將手機(jī)dpi改為160(對(duì)應(yīng)mdpi)如贷,那么這時(shí)候依然會(huì)優(yōu)先讀取xxhdpi下的圖片資源到踏,我試了兩個(gè)不同廠商的手機(jī)都是這樣杠袱。
參考文章:
Android中px dpi dip density densityDpi 的相關(guān)說(shuō)明
DPI、PPI窝稿、DP楣富、PX 的詳細(xì)計(jì)算方法及算法來(lái)源是什么?
ANDROID 屏幕適配
Android 適配時(shí)資源限定符的說(shuō)明
Android drawable微技巧讹躯,你所不知道的drawable的那些細(xì)節(jié)