做Android拭卿,一定會(huì)接觸到屏幕適配墨礁,而屏幕適配的方案也是有多種多樣,這個(gè)話題一直沒有停止榛臼,最近也是想再研究一下適配的多種方式伊佃。
先放一個(gè)表格
密度類型 | 代表的分辨率(px) | 屏幕密度(dpi) | density | 換算(px/dp) | 比例 |
---|---|---|---|---|---|
低密度(ldpi) | 240x320 | 120 | 1dp=0.75px | 0.75 | 3 |
中密度(mdpi) | 320x480 | 160 | 1dp=1px | 1 | 4 |
高密度(hdpi) | 480x800 | 240 | 1dp=1.5px | 1.5 | 6 |
超高密度(xhdpi) | 720x1280 | 320 | 1dp=2px | 2 | 8 |
超超高密度(xxhdpi) | 1080x1920 | 480 | 1dp=3px | 3 | 12 |
再放幾個(gè)公式
計(jì)算屏幕對(duì)角線英寸
計(jì)算density和dpi
計(jì)算dp和px的關(guān)系
一些概念:
density的意思就是1dp等于幾個(gè)px像素點(diǎn)
比如density=3,意思是1dp=3pxdp沛善、dip航揉、dpi、ppi
這四個(gè)是新手容易混淆的金刁,其中dp和dip是一樣的概念帅涂,這個(gè)是android特有的一種邏輯單位议薪,和具體設(shè)備的物理像素?zé)o關(guān)。
而dpi和ppi是一樣的概念媳友,這個(gè)是一平方英寸里有多少個(gè)像素點(diǎn)的意思斯议。不管你在布局文件中填寫的是什么單位,最后都會(huì)被轉(zhuǎn)化為 px
除了下面提到的醇锚,還有比較簡(jiǎn)單有效的適配方法:
比如常使用的:RelativeLayout布局哼御、LinearLayout布局、weight焊唬、.9.png恋昼、svg圖片、ViewStub赶促、include液肌、merge
不長(zhǎng)使用的,比如app需要自動(dòng)適配手機(jī)和平板時(shí)用到的:布局別名芳杏、smallestWidth限定符
詳情可看這里:http://www.reibang.com/p/ec5a1a30694b
先提出以下疑問矩屁,根據(jù)疑問來學(xué)習(xí)
- 如果要開發(fā)一個(gè)新的App辟宗,設(shè)計(jì)人員的底圖應(yīng)該多大爵赵?
- 切圖后,把圖片放到res下面的哪個(gè)文件夾泊脐?
- 如果使用warp_content空幻,那么這個(gè)大小在不同dpi設(shè)備里是多大的px?
根據(jù)以上疑問容客,我們來一一解答
很多時(shí)候有經(jīng)驗(yàn)的設(shè)計(jì)人員給我們的原型里秕铛,已經(jīng)有了dp值,但是有些設(shè)計(jì)新人并不知道如何在原型里標(biāo)注多大的dp值缩挑,而且很多時(shí)候設(shè)計(jì)都是按照ios的分辨率來切圖的但两,我們先說按照android標(biāo)準(zhǔn)尺寸切圖的情況,假設(shè)我們使用1920*1080分辨率的底圖
使用1920*1080分辨率作為底圖設(shè)計(jì)切圖后供置,我們盡量把切圖放在高dpi文件夾里(設(shè)計(jì)底圖分辨率不要太低谨湘,如1920*1080就比較清晰),否則放在低dpi文件夾里的話芥丧,如果app安裝在高dpi的手機(jī)設(shè)備里紧阔,圖片會(huì)拉伸,可能會(huì)模糊续担,現(xiàn)在一般至少1920*1080分辨率擅耽,這個(gè)分辨率的谷歌標(biāo)準(zhǔn)dpi是480,也就是xxhdpi
3.1. 如果我們將切圖放到了res/xxhdpi下面物遇,根據(jù)谷歌設(shè)計(jì)規(guī)范這個(gè)dpi的density是3乖仇,如果1080px*1920px分辨率的底圖中有一個(gè)圖片是540px*960px(在density等于3時(shí)等同于180dp*320dp)憾儒,那么這個(gè)圖片使用warp_content的話在1080px*1920px(在density等于3時(shí)等同于360dp*640dp)分辨率并且density等于3的設(shè)備上顯示時(shí)寬度正好是屏幕寬度的一半(比較dp的話是540px/3density=180dp是360dp的一半,比較px的話是540px是1080px的一半)
-
3.2. 如果我們將切圖位置不變乃沙,仍然放到了res/xxhdpi(density=3)下面航夺,那么該540px*960px分辨率的圖片在xhdpi(density=2)的設(shè)備里使用warp_content自適應(yīng)時(shí)的分辨率和dp是多少呢?
- 先算一下px:xxhdpi下面的dp是540px/3density=180dp崔涂,180dp*2density=360px阳掐,所以這個(gè)圖片使用warp_content自適應(yīng)時(shí)的在xhdpi下面分辨率是360px
- 而dp就是這個(gè)圖片在當(dāng)前所在dpi設(shè)備里(也可以說當(dāng)前所在dpi文件夾里)的dp,這個(gè)dp就是在所有dpi設(shè)備里的dp冷蚂,如當(dāng)前圖片在xxhdpi下面缭保,所以dp是540px/3density=180dp,在xhdpi蝙茶、hdpi等等里面也都是這個(gè)dp艺骂。
- 總結(jié)一下:圖片在當(dāng)前dpi文件夾里warp_content自適應(yīng)時(shí)的dp是多大,在其他所有dpi顯示設(shè)備里的dp也是多大隆夯,所以先計(jì)算圖片在當(dāng)前dpi文件夾里warp_content自適應(yīng)時(shí)的dp钳恕,然后根據(jù)這個(gè)dp和其他dpi設(shè)備的density就可以計(jì)算出這個(gè)圖片顯示在非當(dāng)前dpi設(shè)備里時(shí)的分辨率大小。
3.3. 如果我們將剛才540px*960px的切圖放到res/xhdpi下面的話(xhdpi的density是2蹄衷,所以等同于270dp*480dp)忧额,那么這個(gè)圖片使用warp_content的話在xhdpi(density=2時(shí)xhdpi是360dp寬640dp高)的設(shè)備上顯示時(shí)這個(gè)圖片寬度要大于屏幕寬度的一半,不信的可以試一下愧口,我試過了沒錯(cuò)(比較dp的話是270dp是360dp的0.75倍睦番,比較px的話是540px是720px的0.75倍)
根據(jù)上面這些內(nèi)容可以總結(jié)得到以下結(jié)論:
- 如果設(shè)計(jì)人員給的底圖使用某個(gè)谷歌標(biāo)準(zhǔn)分辨率,比如1920*1080耍属,根據(jù)最開始的表格可以看到這個(gè)分辨率對(duì)應(yīng)的res文件夾是xxhdpi托嚣,如果把切圖放到這個(gè)文件夾里,那么圖片自適應(yīng)的寬高和設(shè)計(jì)圖是一樣的厚骗,如果其中需要指定大小示启,可以根據(jù)公式dp=px/density來得到。也就是說如果底圖是谷歌標(biāo)準(zhǔn)分辨率领舰,把底圖或者切圖放到對(duì)應(yīng)的res文件夾里夫嗓,視覺效果和設(shè)計(jì)圖是一樣的。
但是提揍,比如在1920*1080底圖中有一個(gè)切圖是1920*540啤月,那么放到xxhdpi里,在xml使用寬度使用warp_content和使用180dp(540px/3density計(jì)算的來)劳跃,都是占用標(biāo)準(zhǔn)xxhdpi模擬器的一半寬(180dp*3density=540px谎仲,540px是1080px的一半;或者直接看dp刨仑,180dp是360dp的一半)郑诺。但是如果換一個(gè)模擬器(圖片仍然在xxhdpi文件夾下)夹姥,換的模擬器不一定是360dp寬,那么這個(gè)切圖就不一定是占據(jù)模擬器一半的寬度了辙诞。在420dpi的模擬器里辙售,這個(gè)模擬器的density是420/160=2.625,所以這個(gè)模擬器的寬約等于411dp飞涂,這個(gè)圖片占據(jù)屏幕的180/411這么寬旦部,看起來小于一半(或者看分辨率,180dp*2.625density=472.5px较店,472.5px/1080px小于一半)士八。而如果在320dp的模擬器里顯示的話(標(biāo)準(zhǔn)hdpi就是320dp寬),這個(gè)圖片占據(jù)屏幕的180/320這么寬梁呈,看起來大于一半婚度。
備注:以上計(jì)算方式必須知道設(shè)備的dpi或者density其中一個(gè),否則無法計(jì)算官卡。(density=dpi/160)
假如知道某個(gè)圖片在某個(gè)dpi文件夾里的warp_content時(shí)的px值蝗茁,想知道這個(gè)圖片放在其他dpi文件夾里的warp_content時(shí)的px值,可以通過 px/當(dāng)前dpi設(shè)備的density 得到這個(gè)圖片在當(dāng)前dpi下面的dp值寻咒,然后根據(jù)該 dp值*其他dpi設(shè)備的density 得到該圖片放在其他dpi設(shè)備里的px值哮翘。
- 如果設(shè)計(jì)人員給的底圖不是某個(gè)谷歌標(biāo)準(zhǔn)分辨率(一般都不是標(biāo)準(zhǔn)分辨率),比如是用的iphone6設(shè)計(jì)的底圖(配置:1334×750分辨率仔涩,326dpi)忍坷,我們有以下方法可以來適配:如窮舉分辨率適配法、smallestWidth適配法等等熔脂,下面我們一一列舉。
所以一個(gè)新項(xiàng)目我們可以讓設(shè)計(jì)按照某個(gè)谷歌標(biāo)準(zhǔn)分辨率做底圖柑肴,然后根據(jù)上面的規(guī)則我們就知道圖中對(duì)應(yīng)的px在某個(gè)dpi文件夾里是多少dp霞揉。
1. 窮舉分辨率適配法
簡(jiǎn)單說,就是窮舉市面上所有的Android手機(jī)的寬高像素值晰骑,然后創(chuàng)建一批不同分辨率下的dimen文件适秩,其中值的單位是px:
設(shè)定一個(gè)基準(zhǔn)的分辨率,其他分辨率都根據(jù)這個(gè)基準(zhǔn)分辨率來計(jì)算硕舆,在不同的尺寸文件夾內(nèi)部秽荞,根據(jù)該尺寸編寫對(duì)應(yīng)的dimens文件。
比如以480x320為基準(zhǔn)分辨率
寬度為320抚官,將任何分辨率的寬度整分為320份扬跋,取值為x1-x320
高度為480,將任何分辨率的高度整分為480份凌节,取值為y1-y480
那么對(duì)于480*800的分辨率的dimens文件來說钦听,
x1=(480/320)*1=1.5px
x2=(480/320)*2=3px
...
這個(gè)時(shí)候洒试,我們用UI設(shè)計(jì)界面作為基準(zhǔn)分辨率,比如UI設(shè)計(jì)界面是640px*960px朴上,然后我們創(chuàng)建values-640x960垒棋,然后創(chuàng)建一堆dimen值,分別是x1-x640痪宰,值從1px-640px叼架,如果我們要使用1000px怎么辦呢?我們可以將dimen的范圍寫大一些也可以的衣撬,只要比例一樣就行碉碉。
然后我們可以根據(jù)這個(gè)基準(zhǔn)分辨率創(chuàng)建其他分辨率的文件,比如創(chuàng)建
values-480x800淮韭,x1就是480/640=0.75px垢粮,其他值根據(jù)此比例來生成。
當(dāng)APP運(yùn)行在不同分辨率的手機(jī)中時(shí)靠粪,這些系統(tǒng)會(huì)根據(jù)這些dimens引用去該分辨率的文件夾下面尋找對(duì)應(yīng)的值蜡吧。這樣基本解決了我們的適配問題,而且極大的提升了我們UI開發(fā)的效率占键。
但是這個(gè)方案有一個(gè)致命的缺陷昔善,那就是需要精準(zhǔn)命中才能適配,比如1920*1080的手機(jī)就一定要找到1920*1080的限定符畔乙,否則就只能用統(tǒng)一的默認(rèn)的dimens文件了君仆。而使用默認(rèn)的尺寸的話,UI就很可能變形牲距,簡(jiǎn)單說返咱,就是容錯(cuò)機(jī)制很差。
不過這個(gè)方案有一些團(tuán)隊(duì)用過牍鞠,我們可以認(rèn)為它是一個(gè)比較成熟有效的方案了咖摹。
2. smallestWidth適配法或者叫sw限定符適配法
這個(gè)和上面的區(qū)別是窮舉市面上所有手機(jī)的dp值,dimen的單位是dp难述,該方法解決了上面方法1的缺點(diǎn)萤晴,即使某個(gè)dp沒有覆蓋,系統(tǒng)也會(huì)尋找小于或等于該dp的文件胁后,然后用該文件適配店读。這種機(jī)制和上文提到的寬高限定符適配原理上是一樣的,都是系統(tǒng)通過特定的規(guī)則來選擇對(duì)應(yīng)的文件攀芯。
這種適配方式的dimen文件的生成的規(guī)則和上面一樣屯断,也是先設(shè)置一個(gè)基準(zhǔn)dp,因?yàn)橄到y(tǒng)會(huì)根據(jù)當(dāng)前設(shè)備的最小dp去選擇文件夾,所以我們把設(shè)計(jì)圖的px當(dāng)成dp作為基準(zhǔn)dp就可以了裹纳,舉個(gè)例子择葡,我們的UI設(shè)計(jì)圖是640px*960px,我們把它當(dāng)成640dp*960dp剃氧,然后我們創(chuàng)建基準(zhǔn)dp文件夾values-sw640dp敏储,我們可以從1創(chuàng)建到分辨率的最大值,比如x1=1dp朋鞍,x640=640dp已添,x960=960dp,然后我們可以其他sw<N>dp文件夾滥酥,比如創(chuàng)建values-sw480dp文件夾更舞,480/640=0.75,所以x1=0.75dp坎吻,以此類推x640*0.75=480dp缆蝉,x960*0.75=720dp,看到了吧瘦真,我們直接用UI設(shè)計(jì)圖的分辨率作為基準(zhǔn)分辨率即可刊头,然后使用的時(shí)候設(shè)計(jì)圖中的10px我們用x10就可以了,很方便诸尽。同樣的我們也可以創(chuàng)建layout-sw<N>dp原杂,在不同dpi的設(shè)備里系統(tǒng)會(huì)自動(dòng)選擇對(duì)應(yīng)的layout
思考一下:如果一個(gè)相同name的dimen在values-分辨率文件夾和values-swdp文件夾里都定義了的時(shí)候系統(tǒng)會(huì)使用哪個(gè)值?我測(cè)試了一下您机,系統(tǒng)會(huì)優(yōu)先使用values-swdp文件夾里的值穿肄。
這個(gè)方案的缺點(diǎn):
在布局中引用 dimens 的方式,雖然學(xué)習(xí)成本低际看,但是在日常維護(hù)修改時(shí)較麻煩
侵入性高咸产,如果項(xiàng)目想切換為其他屏幕適配方案,因?yàn)槊總€(gè) Layout 文件中都存在有大量 dimens 的引用仿村,這時(shí)修改起來工作量非常巨大锐朴,切換成本非常高昂
無法覆蓋全部機(jī)型,想覆蓋更多機(jī)型的做法就是生成更多的資源文件蔼囊,但這樣會(huì)增加 App 體積,在沒有覆蓋的機(jī)型上還會(huì)出現(xiàn)一定的誤差衣迷,所以有時(shí)需要在適配效果和占用空間上做一些抉擇
如果想使用 sp畏鼓,也需要生成一系列的 dimens壶谒,導(dǎo)致再次增加 App 的體積
不能自動(dòng)支持橫豎屏切換時(shí)的適配,如上文所說汗菜,如果想自動(dòng)支持橫豎屏切換時(shí)的適配挑社,需要使用 values-w<N>dp 或 屏幕方向限定符 再生成一套資源文件巡揍,這樣又會(huì)再次增加 App 的體積
3. 美團(tuán)的修改density適配法
我們強(qiáng)制將density修改為谷歌標(biāo)準(zhǔn)值,也就相當(dāng)于我們強(qiáng)制把設(shè)計(jì)人員給的圖片轉(zhuǎn)為谷歌某個(gè)標(biāo)準(zhǔn)分辨率阱当,這樣我們上面的計(jì)算方法就有效了,通過測(cè)試某個(gè)切圖發(fā)現(xiàn)不同dp寬度的模擬器中該圖片在屏幕的比例都是一致的弊添。但是修改了系統(tǒng)的density值之后捌木,整個(gè)布局的實(shí)際尺寸都會(huì)發(fā)生改變,如果想要在老項(xiàng)目文件中使用刨裆,恐怕整個(gè)布局文件中的尺寸都可能要重新按照設(shè)計(jì)稿修改一遍才行。因此崔拥,如果你是在維護(hù)或者改造老項(xiàng)目,使用這套方案就要三思了链瓦。
我先發(fā)一下美團(tuán)方式的計(jì)算公式
public class Test {
private static float sNonCompatDensity;
private static float sNonCompatScaledDensity;
public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application, final int designWidthDp) {
final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
if (sNonCompatDensity == 0) {
sNonCompatDensity = appDisplayMetrics.density;
sNonCompatScaledDensity = appDisplayMetrics.scaledDensity;
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
sNonCompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
final float targetDensity = appDisplayMetrics.widthPixels / ((float) (designWidthDp));
final float targetScaledDensity = targetDensity * (sNonCompatScaledDensity / sNonCompatDensity);
final int targetDensityDpi = (int) (160 * targetDensity);
appDisplayMetrics.density = targetDensity;
appDisplayMetrics.scaledDensity = targetScaledDensity;
appDisplayMetrics.densityDpi = targetDensityDpi;
final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
}
}
美團(tuán)這種方式如何使用呢拆魏,比如設(shè)計(jì)人員的底圖分辨率是W*H(豎屏,并且W<H)慈俯,如果你要適配1080*1920(xxhdpi)也就是說你想把切圖放到xxhdpi的文件夾下面渤刃,而1080*1920的谷歌標(biāo)準(zhǔn)是360dp寬(1080/xxhdpi的density),所以Wpx相對(duì)于1080px底圖也就是然后計(jì)算得到Wdp的值贴膘,然后把這個(gè)圖片和切圖放到xxhdpi下面卖子,在Activity的onCreate方法的setContentView前面調(diào)用
Test.setCustomDensity(this, application,Wdp)
,然后顯示效果是和設(shè)計(jì)圖一樣的
舉個(gè)例子刑峡,比如設(shè)計(jì)人員的底圖是500*1000洋闽,其中有個(gè)切圖是500*1000,然后如果你要適配1080*1920(xxhdpi)突梦,而1080*1920的谷歌標(biāo)準(zhǔn)是360dp寬(1080/xxhdpi的density)诫舅,所以500px相對(duì)于1080px底圖也就是500/1080*360=167dp,然后把這個(gè)圖片放到xxhdpi下面宫患,然后調(diào)用Test.setCustomDensity(this, application,167)
刊懈,這樣就會(huì)在任何模擬器里這個(gè)圖片看起來寬度都是正好占滿屏幕寬度。
而如果要適配720*1280(xhpdi),而720*1280的谷歌標(biāo)準(zhǔn)是360dp寬(720/xhdpi的density)虚汛,所以500px相對(duì)于1080px底圖也就是500/1080*360=167dp匾浪,然后把這個(gè)圖片放到xhpdi下面,然后調(diào)用Test.setCustomDensity(this, application,167)
而如果要適配480*800(hpdi)卷哩,而480*800的谷歌標(biāo)準(zhǔn)是320dp寬(480/hdpi的density)蛋辈,所以500px相對(duì)于480px底圖也就是500/480*320=333dp,然后把這個(gè)圖片放到hpdi下面殉疼,然后調(diào)用Test.setCustomDensity(this, application,333)
但是這個(gè)方式也有缺點(diǎn):
這個(gè)方案依賴于設(shè)計(jì)圖尺寸梯浪,但是項(xiàng)目中的系統(tǒng)控件、三方庫(kù)控件瓢娜、等非我們項(xiàng)目自身設(shè)計(jì)的控件挂洛,它們的設(shè)計(jì)圖尺寸并不會(huì)和我們項(xiàng)目自身的設(shè)計(jì)圖尺寸一樣
當(dāng)這個(gè)適配方案不分類型,將所有控件都強(qiáng)行使用我們項(xiàng)目自身的設(shè)計(jì)圖尺寸進(jìn)行適配時(shí)眠砾,這時(shí)就會(huì)出現(xiàn)問題虏劲,當(dāng)某個(gè)系統(tǒng)控件或三方庫(kù)控件的設(shè)計(jì)圖尺寸和和我們項(xiàng)目自身的設(shè)計(jì)圖尺寸差距非常大時(shí)柒巫,這個(gè)問題就越嚴(yán)重堡掏。
解決方案有兩種:
方案 1
調(diào)整設(shè)計(jì)圖尺寸泉唁,因?yàn)槿綆?kù)可能是遠(yuǎn)程依賴的亭畜,無法修改源碼拴鸵,也就無法讓三方庫(kù)來適應(yīng)我們項(xiàng)目的設(shè)計(jì)圖尺寸劲藐,所以只有我們自身作出修改瘩燥,去適應(yīng)三方庫(kù)的設(shè)計(jì)圖尺寸,我們將項(xiàng)目自身的設(shè)計(jì)圖尺寸修改為這個(gè)三方庫(kù)的設(shè)計(jì)圖尺寸二拐,就能完成項(xiàng)目自身和三方庫(kù)的適配
這時(shí)項(xiàng)目的設(shè)計(jì)圖尺寸修改了百新,所以項(xiàng)目布局文件中的 dp 值仗哨,也應(yīng)該按照修改的設(shè)計(jì)圖尺寸厌漂,按比例增減苇倡,保持與之前設(shè)計(jì)圖中的比例不變
但是如果為了適配一個(gè)三方庫(kù)修改整個(gè)項(xiàng)目的設(shè)計(jì)圖尺寸旨椒,是非常不值得的综慎,所以這個(gè)方案支持以 Activity 為單位修改設(shè)計(jì)圖尺寸示惊,相當(dāng)于每個(gè) Activity 都可以自定義設(shè)計(jì)圖尺寸涝涤,因?yàn)橛行?Activity 不會(huì)使用三方庫(kù) View阔拳,也就不需要自定義尺寸糊肠,所以每個(gè) Activity 都有控制權(quán)的話货裹,這也是最靈活的
但這也有個(gè)問題弧圆,當(dāng)一個(gè) Activity 使用了多個(gè)設(shè)計(jì)圖尺寸不一樣的三方庫(kù) View霹期,就會(huì)同樣出現(xiàn)上面的問題历造,這也就只有把設(shè)計(jì)圖改為與幾個(gè)三方庫(kù)比較折中的尺寸吭产,才能勉強(qiáng)緩解這個(gè)問題
方案 2
第二個(gè)方案是最簡(jiǎn)單的臣淤,也是按 Activity 為單位荒典,取消當(dāng)前 Activity 的適配效果寺董,改用其他的適配方案
該方案的補(bǔ)充與擴(kuò)展:
https://juejin.im/post/5b7fafb351882542af1c75ad
4. 有人修改了與完善了美團(tuán)的這種方式遮咖,如今日頭條的方案
https://juejin.im/post/5bce688e6fb9a05cf715d1c2
至此完成本篇文章御吞,可能有的地方有些啰嗦陶珠,我是想盡可能講的詳細(xì)一些揍诽,我把jess中的文章有些不清楚的地方我添加了一些解釋
其他一些適配方式:
使用鴻洋大神的軟件生成大量px文件放到項(xiàng)目中
這種方式,是根據(jù)dp狐肢、density碟联、px換算出來一堆px文件,分辨對(duì)應(yīng)不同分辨率的手機(jī)部脚,能解決大部分的適配問題,但是如果遇到分辨率比較高但是屏幕尺寸比較大的時(shí)候鹰椒,這個(gè)設(shè)備的dpi會(huì)比較低漆际,然后就會(huì)有些問題奸汇,而且這樣也會(huì)有一大堆"values-寬X高"文件夾擂找,里面有一大堆的px文件贯涎,增加apk體積塘雳。這時(shí)候應(yīng)該可以再創(chuàng)建類似values-160dpi這種文件夾來解決,而且可以創(chuàng)建values-160dpi-1024x600這種文件夾太防,這些文件夾可以混用盈包,優(yōu)先用更精確的那個(gè)呢燥。使用鴻洋大神的AutoLayout框架
這個(gè)方式也不錯(cuò)叛氨,里面的源碼我還沒仔細(xì)看,我們公司也用的這種方式屁置,不過有些控件會(huì)有問題蓝角,針對(duì)這些控件鴻洋有一些重寫使鹅,不過沒有的就需要自己去寫了約束布局(ConstraintLayout),這個(gè)我還沒怎么去了解炊苫,待這幾天看看研究一下再來完善該篇文章执虹,在這篇文檔里:https://developer.android.com/reference/android/support/percent/package-summary 声畏,谷歌明確表示廢棄了百分比布局庫(kù)插龄,而應(yīng)該使用約束布局均牢。
-
使用pt物理單位
源鏈接: http://www.apkbus.com/blog-177177-76719.html
涉及到的代碼: https://github.com/Firedamp/Rudeness/blob/daad96fc6bcef8579fefdfc8e8ddc1046c89d26a/rudeness-sdk/src/main/java/com/bulong/rudeness/RudenessScreenHelper.java
在上面這個(gè)鏈接里有段代碼是resources.getDisplayMetrics().xdpi = size.x/designWidth*72f;
在android系統(tǒng)里有個(gè)方法是這樣的
public static float applyDimension(int unit, float value, DisplayMetrics metrics){ switch (unit) { case COMPLEX_UNIT_PX: return value; case COMPLEX_UNIT_DIP: return value * metrics.density; case COMPLEX_UNIT_SP: return value * metrics.scaledDensity; case COMPLEX_UNIT_PT: return value * metrics.xdpi * (1.0f/72); case COMPLEX_UNIT_IN: return value * metrics.xdpi; case COMPLEX_UNIT_MM: return value * metrics.xdpi * (1.0f/25.4f); } return 0; }
value * metrics.xdpi * (1.0f/72) = 該控件實(shí)際顯示的px值
可以換算為metrics.xdpi = 該控件實(shí)際顯示的px值/value*72
,其中value
是該控件在設(shè)計(jì)圖顯示的pt值大小
而我們要保證這個(gè)控件在任何分辨率下都相對(duì)于屏幕大小有固定的比例徘跪,只需要讓控件實(shí)際顯示的px值/value=實(shí)際屏幕顯示的px值/實(shí)際屏幕的pt值大小
,也就是resources.getDisplayMetrics().xdpi = size.x/designWidth*72f
參考文章較多哨查,記錄幾個(gè)
http://www.reibang.com/p/c772cf49469a
http://www.apkbus.com/blog-177177-76719.html