屏幕適配

做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è)公式

  1. 計(jì)算屏幕對(duì)角線英寸
    屏幕對(duì)角線=\sqrt{分辨率高^2+分辨率寬^2} \div dpi

  2. 計(jì)算density和dpi
    density=dpi \div 160
    density * 160=dpi

  3. 計(jì)算dp和px的關(guān)系
    dp=px\div density
    density=px\div dp
    px=dp * density

一些概念:

  1. density的意思就是1dp等于幾個(gè)px像素點(diǎn)
    比如density=3,意思是1dp=3px

  2. dp沛善、dip航揉、dpi、ppi
    這四個(gè)是新手容易混淆的金刁,其中dp和dip是一樣的概念帅涂,這個(gè)是android特有的一種邏輯單位议薪,和具體設(shè)備的物理像素?zé)o關(guān)。
    而dpi和ppi是一樣的概念媳友,這個(gè)是一平方英寸里有多少個(gè)像素點(diǎn)的意思斯议。

  3. 不管你在布局文件中填寫的是什么單位,最后都會(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í)

  1. 如果要開發(fā)一個(gè)新的App辟宗,設(shè)計(jì)人員的底圖應(yīng)該多大爵赵?
  2. 切圖后,把圖片放到res下面的哪個(gè)文件夾泊脐?
  3. 如果使用warp_content空幻,那么這個(gè)大小在不同dpi設(shè)備里是多大的px?

根據(jù)以上疑問容客,我們來一一解答

  1. 很多時(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分辨率的底圖

  2. 使用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é)論:

  1. 如果設(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值哮翘。

  1. 如果設(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:


image.png

設(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

...


image.png

這個(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底圖也就是\cfrac{Wpx}{1080px}=\cfrac{Wdp}{360dp}然后計(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中的文章有些不清楚的地方我添加了一些解釋


其他一些適配方式:

  1. 使用鴻洋大神的軟件生成大量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è)呢燥。

  2. 使用鴻洋大神的AutoLayout框架
    這個(gè)方式也不錯(cuò)叛氨,里面的源碼我還沒仔細(xì)看,我們公司也用的這種方式屁置,不過有些控件會(huì)有問題蓝角,針對(duì)這些控件鴻洋有一些重寫使鹅,不過沒有的就需要自己去寫了

  3. 約束布局(ConstraintLayout),這個(gè)我還沒怎么去了解炊苫,待這幾天看看研究一下再來完善該篇文章执虹,在這篇文檔里:https://developer.android.com/reference/android/support/percent/package-summary 声畏,谷歌明確表示廢棄了百分比布局庫(kù)插龄,而應(yīng)該使用約束布局均牢。

  4. 使用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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寒亥,一起剝皮案震驚了整個(gè)濱河市溉奕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仙辟,老刑警劉巖欺嗤,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異校赤,居然都是意外死亡马篮,警方通過查閱死者的電腦和手機(jī)浑测,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滥崩,“玉大人蜂科,你說我怎么就攤上這事短条∪资保” “怎么了屹蚊?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)田晚。 經(jīng)常有香客問我,道長(zhǎng)汇四,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任序宦,我火速辦了婚禮互捌,結(jié)果婚禮上秕噪,老公的妹妹穿的比我還像新娘腌巾。我一直安慰自己铲觉,他們只是感情好碉克,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布漏麦。 她就那樣靜靜地躺著撕贞,像睡著了一般捏膨。 火紅的嫁衣襯著肌膚如雪目胡。 梳的紋絲不亂的頭發(fā)上链快,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天巨双,我揣著相機(jī)與錄音筑累,去河邊找鬼慢宗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的湘换。 我是一名探鬼主播彩倚,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼帆离,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了麻献?” 一聲冷哼從身側(cè)響起们妥,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勉吻,沒想到半個(gè)月后监婶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年惑惶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了煮盼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡带污,死狀恐怖僵控,靈堂內(nèi)的尸體忽然破棺而出喉祭,到底是詐尸還是另有隱情翘紊,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布绍妨,位于F島的核電站倒堕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一怒允、第九天 我趴在偏房一處隱蔽的房頂上張望丽惶。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)担租。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間娄徊,已是汗流浹背中鼠。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人天吓。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓滔金,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親屹徘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惩琉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容