今日頭條適配方案解讀即常用適配方案總結(jié)

前段時(shí)間今日頭條開源了屏幕適配方案坚弱,前段時(shí)間大體的看了一下稍味,正好這兩天有時(shí)間隧熙,仔細(xì)研究一下和總結(jié)一下適配方案婉弹。

在了解適配方案之前睬魂,先來一遍dp,dpi,density概念吧!

px : 是pixel的縮寫镀赌,pixel即像素,平時(shí)所說的設(shè)備的分辨率是多少氯哮,這里的單位就是px。

dp: 指的是設(shè)備獨(dú)立像素商佛,以dp為尺寸單位的控件喉钢,在不同分辨率和尺寸的手機(jī)上代表了不同的真實(shí)像素,比如在分辨率較低的手機(jī)中良姆,可能1dp=1px,而在分辨率較高的手機(jī)中出牧,可能1dp=2px⌒危或者是1dp=3px;

那么這個(gè)dp是如何計(jì)算的呢?

我們都知道一個(gè)公式: px = dp(dpi/160) 系統(tǒng)都是通過這個(gè)來判斷px和dp的數(shù)學(xué)關(guān)系评抚,那么這里又出現(xiàn)了一個(gè)問題豹缀,dpi是什么呢?

dpi:是像素密度慨代,指的是在系統(tǒng)軟件上指定的單位尺寸的像素?cái)?shù)量邢笙,它往往是寫在系統(tǒng)出廠配置文件的一個(gè)固定值。

屏幕尺寸侍匙、像素密度氮惯、分辨率的三者關(guān)系:
dpi關(guān)系.png

1、dp適配解決方案:

android中在渲染屏幕時(shí)想暗,都會(huì)將我們在xml中的dp單位轉(zhuǎn)化為px,去渲染到設(shè)備中妇汗,用到的轉(zhuǎn)換單位如下:
px =dp * density;
density=dpi/160;
px=dp*(dpi/160);
而dpi是根據(jù)設(shè)備的屏幕真實(shí)分辨率和尺寸大小進(jìn)行計(jì)算得到的,每個(gè)設(shè)備可能不一樣说莫,這也是Android設(shè)備進(jìn)行碎片化的原因杨箭,和總是有人進(jìn)行探索適配方案的原因。

假如設(shè)備的分辨率為1920*1080,屏幕大小為5英寸储狭,則通過上面的換算公式則得到該設(shè)備的dpi為 :對角線的像素個(gè)數(shù) 2203/屏幕大小5=440dpi,由此得到density=440/160=2.75 互婿,由此可以換算出屏幕寬度的dp=1080/2.75=392dp

但是捣郊,假如我們的UI給的設(shè)計(jì)圖為360dp的,這種情況慈参,顯然屏幕尺寸要比設(shè)計(jì)圖寬呛牲,這種情況下,即使使用dp適配驮配,也很難達(dá)到不同設(shè)備之間顯示相同的效果娘扩,還有可能出現(xiàn)部分設(shè)備展示不全的情況。

而且上述屏幕尺寸僧凤、分辨率和像素密度的關(guān)系畜侦,很多設(shè)備并沒有按此規(guī)則來實(shí)現(xiàn), 因此dpi的值非常亂躯保,沒有規(guī)律可循旋膳,從而導(dǎo)致使用dp適配效果差強(qiáng)人意。

一般給我們的設(shè)計(jì)圖原則為:

7201280的分辨率途事,density為2验懊,
1080
1920的分辨率,density為3尸变,(常見情況)
1440*2560的分辨率义图,density為4,

所以召烂,一般會(huì)以360dp去適配應(yīng)用程序(即640dp*36dp)碱工,故如上的設(shè)備顯然要比設(shè)計(jì)圖寬,那怎么辦呢奏夫?再回頭看這個(gè)公式

px=dp*density

屏幕的像素值每個(gè)設(shè)備已經(jīng)是固定的怕篷,即px固定,當(dāng)設(shè)計(jì)圖出來的時(shí)候酗昼,一般dp也是固定的廊谓,即如上介紹的360dp,為了在不同的設(shè)備上顯示相同的效果,所以只能修改density麻削。

每個(gè)設(shè)備的分辨率和尺寸大小的不同蒸痹,則density會(huì)有好多種,而要實(shí)現(xiàn)不同的設(shè)備之間顯示相同的效果呛哟,只要修改density為我們希望的density叠荠,覆蓋掉系統(tǒng)本身的density即可, density=screenWidth/360,這里360看實(shí)際情況竖共,看UI給的設(shè)計(jì)圖的到底是多大的蝙叛。如果我們想在所有設(shè)備上顯示完全一致,其實(shí)是不現(xiàn)實(shí)的公给,因?yàn)槠聊桓邔挶炔皇枪潭ǖ模?6:9借帘、4:3甚至其他寬高比層出不窮蜘渣,寬高比不同,顯示完全一致就不可能了肺然。

只要在一個(gè)維度上進(jìn)行適配蔫缸,也就是說假如頁面是上下滑動(dòng)的,我們只要確定好寬度這一個(gè)維度適配好即可际起,同理拾碌,如果頁面是左右滑動(dòng)的,只要設(shè)置好高度這個(gè)維度就可以街望。

如上是今日頭條團(tuán)隊(duì)的解決方案,即動(dòng)態(tài)的修改設(shè)備的density值校翔,達(dá)到不同分辨率設(shè)備的適配。

640.jpeg

blankj大佬的封裝的解決方案:附上地址:https://github.com/Blankj/AndroidUtilCode
核心代碼如下:

    private static void adaptScreen(final Activity activity,
                                    final int sizeInPx,
                                    final boolean isVerticalSlide) {
        final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
        final DisplayMetrics appDm = App.getAppContext().getResources().getDisplayMetrics();
        final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();
        if (isVerticalSlide) {
            activityDm.density = activityDm.widthPixels / (float) sizeInPx;
        } else {
            activityDm.density = activityDm.heightPixels / (float) sizeInPx;
        }
        activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density);
        activityDm.densityDpi = (int) (160 * activityDm.density);
        appDm.density = activityDm.density;
        appDm.scaledDensity = activityDm.scaledDensity;
        appDm.densityDpi = activityDm.densityDpi;
    }

假如要使用第三方的UI界面的時(shí)候灾前,重新設(shè)置為系統(tǒng)的density即可

    public static void cancelAdaptScreen(final Activity activity) {
        final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics();
        final DisplayMetrics appDm = App.getAppContext().getResources().getDisplayMetrics();
        final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics();
        activityDm.density = systemDm.density;
        activityDm.scaledDensity = systemDm.scaledDensity;
        activityDm.densityDpi = systemDm.densityDpi;
        appDm.density = systemDm.density;
        appDm.scaledDensity = systemDm.scaledDensity;
        appDm.densityDpi = systemDm.densityDpi;
    }

這里展示一下如上適配方案適配效果:

480*800分辨率手機(jī)防症,density為1.5

480*800.png

768*1280分辨率手機(jī),density為2:

768*1280.png

800*1280的平板哎甲,density為1.5

800*1280

1080*1920分辨率手機(jī) 蔫敲,density為3:

image.png

2、寬高限定符適配

簡單說炭玫,就是窮舉市面上所有的Android手機(jī)的寬高像素值即:


image.png

這個(gè)時(shí)候奈嘿,如果我們的UI設(shè)計(jì)界面使用的就是基準(zhǔn)分辨率,那么我們就可以按照設(shè)計(jì)稿上的尺寸填寫相對應(yīng)的dimens引用了,而當(dāng)APP運(yùn)行在不同分辨率的手機(jī)中時(shí)吞加,這些系統(tǒng)會(huì)根據(jù)這些dimens引用去該分辨率的文件夾下面尋找對應(yīng)的值裙犹。這樣基本解決了我們的適配問題,而且極大的提升了我們UI開發(fā)的效率衔憨。

但是這個(gè)方案有一個(gè)致命的缺陷伯诬,那就是需要精準(zhǔn)命中才能適配,比如1920x1080的手機(jī)就一定要找到1920x1080的限定符巫财,否則就只能用統(tǒng)一的默認(rèn)的dimens文件了。而使用默認(rèn)的尺寸的話哩陕,UI就很可能變形平项,簡單說,就是容錯(cuò)機(jī)制很差悍及,而且再一些機(jī)型上面闽瓢,即使配置了,也不會(huì)去對應(yīng)的分辨率下去找心赶。

3扣讼、smallestWidth適配

smallestWidth適配,或者叫sw限定符適配缨叫。指的是Android會(huì)識別屏幕可用高度和寬度的最小尺寸的dp值(其實(shí)就是手機(jī)的寬度值)椭符,然后根據(jù)識別到的結(jié)果去資源文件中尋找對應(yīng)限定符的文件夾下的資源文件荔燎。

這種機(jī)制和上文提到的寬高限定符適配原理上是一樣的,都是系統(tǒng)通過特定的規(guī)則來選擇對應(yīng)的文件销钝。

舉個(gè)例子有咨,小米5s的dpi是480,橫向像素是1080px,根據(jù)px=dp(dpi/160)蒸健,橫向的dp值是1080/(480/160),也就是360dp,系統(tǒng)就會(huì)去尋找是否存在value-sw360dp的文件夾以及對應(yīng)的資源文件座享。


sw.png

smallestWidth限定符適配和寬高限定符適配最大的區(qū)別在于,前者有很好的容錯(cuò)機(jī)制似忧,如果沒有value-sw360dp文件夾渣叛,系統(tǒng)會(huì)向下尋找,比如離360dp最近的只有value-sw350dp盯捌,那么Android就會(huì)選擇value-sw350dp文件夾下面的資源文件淳衙。這個(gè)特性就完美的解決了上文提到的寬高限定符的容錯(cuò)問題。
這里展示一下如上適配方案適配效果:

480*800分辨率手機(jī)挽唉,density為1.5

image.png

768*1280分辨率手機(jī)滤祖,density為2:

image.png

800*1280分辨率平板,density為1.5:

image.png

1080*1920分辨率手機(jī) 瓶籽,density為3:

image.png

附上上述Demo地址:https://github.com/OnexZgj/AdapterScreen 待后期完善

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匠童,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子塑顺,更是在濱河造成了極大的恐慌汤求,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件严拒,死亡現(xiàn)場離奇詭異扬绪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)裤唠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門挤牛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人种蘸,你說我怎么就攤上這事墓赴。” “怎么了航瞭?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵诫硕,是天一觀的道長。 經(jīng)常有香客問我刊侯,道長章办,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮藕届,結(jié)果婚禮上挪蹭,老公的妹妹穿的比我還像新娘。我一直安慰自己翰舌,他們只是感情好嚣潜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著椅贱,像睡著了一般懂算。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庇麦,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天计技,我揣著相機(jī)與錄音,去河邊找鬼山橄。 笑死垮媒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的航棱。 我是一名探鬼主播睡雇,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饮醇!你這毒婦竟也來了它抱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤朴艰,失蹤者是張志新(化名)和其女友劉穎观蓄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祠墅,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侮穿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毁嗦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亲茅。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狗准,靈堂內(nèi)的尸體忽然破棺而出芯急,到底是詐尸還是另有隱情,我是刑警寧澤驶俊,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站免姿,受9級特大地震影響饼酿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一故俐、第九天 我趴在偏房一處隱蔽的房頂上張望想鹰。 院中可真熱鬧,春花似錦药版、人聲如沸辑舷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽何缓。三九已至,卻和暖如春还栓,著一層夾襖步出監(jiān)牢的瞬間碌廓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工剩盒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谷婆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓辽聊,卻偏偏與公主長得像纪挎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子跟匆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

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