騷年你的屏幕適配方式該升級(jí)了!-SmallestWidth 限定符適配方案

原文地址: http://www.lxweimin.com/p/2aded8bb6ede

以下是 騷年你的屏幕適配方式該升級(jí)了! 系列文章,歡迎轉(zhuǎn)發(fā)以及分享:

掃描或點(diǎn)擊以下二維碼,加入技術(shù)交流 QQ 群 455850365

前言

ok,根據(jù)上一篇文章 騷年你的屏幕適配方式該升級(jí)了!-今日頭條適配方案 的承諾,本文是這個(gè)系列的第二篇文章,這篇文章會(huì)詳細(xì)講解 smallestWidth 限定符屏幕適配方案

了解我的朋友一定知道,MVPArms 一直使用的是 鴻神AndroidAutoLayout 屏幕適配方案,得益于 AndroidAutoLayout 的便捷,所以我對(duì)屏幕適配領(lǐng)域研究的不是很多,AndroidAutoLayout 停止維護(hù)后,我也一直在找尋著替代方案,直到 今日頭條屏幕適配方案 刷屏,后來(lái)又無(wú)意間看到了 smallestWidth 限定符屏幕適配方案,這才慢慢的將研究方向轉(zhuǎn)向了屏幕適配領(lǐng)域

最近一個(gè)月才開(kāi)始慢慢惡補(bǔ) Android 屏幕適配的相關(guān)知識(shí),對(duì)這兩個(gè)方案也進(jìn)行了更深入的研究,可以說(shuō)從一個(gè)小白慢慢成長(zhǎng)而來(lái),所以我明白小白的痛,因此在上一篇文章 騷年你的屏幕適配方式該升級(jí)了!-今日頭條適配方案 中,把 今日頭條屏幕適配方案 講得非常的細(xì),盡量把每一個(gè)知識(shí)點(diǎn)都描述清晰,深怕小白漏掉每一個(gè)細(xì)節(jié),這篇文章我也會(huì)延續(xù)上一篇文章的優(yōu)良傳統(tǒng),將 smallestWidth 限定符屏幕適配方案 的每一個(gè)知識(shí)點(diǎn)都描述清晰

順便說(shuō)一句,感謝大家對(duì) AndroidAutoSize 的支持,我只是在上一篇文章中提了一嘴我剛發(fā)布的屏幕適配框架 AndroidAutoSize,還沒(méi)給出詳細(xì)的介紹和原理剖析 (原計(jì)劃在本系列的第三篇文章中發(fā)布),AndroidAutoSize 就被大家推上了 Github Trending,一個(gè)多星期就拿了 2k+ stars,隨著關(guān)注度的增加,我在這段時(shí)間里也累壞了,issues 就沒(méi)斷過(guò),不到半個(gè)月就提交了 200 多次 commit,但累并快樂(lè)著,在這里要再次感謝大家對(duì) AndroidAutoSize 的認(rèn)可

談?wù)剬?duì)百分比庫(kù)的看法

是這樣的,在上篇文章中有一些兄弟提了一些觀點(diǎn),我很是認(rèn)同,但是我站在執(zhí)行者的角度來(lái)看待這個(gè)問(wèn)題,也有一些不同的觀點(diǎn),以下是我在上篇文章中的回復(fù)

大家要注意了!這些觀點(diǎn)其實(shí)針對(duì)的是所有以百分比縮放布局的庫(kù),而不只是今日頭條屏幕適配方案,所以這些觀點(diǎn)也同樣適用于 smallestWidth 限定符屏幕適配方案,這點(diǎn)有很多人存在誤解,所以一定要注意!

上圖的每一個(gè)方框都代表一種 Android 設(shè)備的屏幕,Android系統(tǒng)碎片化機(jī)型以及屏幕尺寸碎片化屏幕分辨率碎片化 有多嚴(yán)重大家可以通過(guò) 友盟指數(shù) 了解一下,有些時(shí)候在某些事情的決斷標(biāo)準(zhǔn)上,并不能按照事情的對(duì)錯(cuò)來(lái)決斷,大多數(shù)情況還是要分析成本,收益等多種因素,通過(guò)利弊來(lái)決斷,每個(gè)人的利弊標(biāo)準(zhǔn)又都不一樣,所以每個(gè)人的觀點(diǎn)也都會(huì)有差別,但也都應(yīng)該得到尊重,所以我只是說(shuō)說(shuō)自己的觀點(diǎn),也不否認(rèn)任何人的觀點(diǎn)

方案是死的人是活的,在某些大屏手機(jī)或平板電腦上,您也可以采用其他適配方案和百分比庫(kù)結(jié)合使用,比如針對(duì)某個(gè)屏幕區(qū)間的設(shè)備單獨(dú)出一套設(shè)計(jì)圖以顯示比小屏幕手機(jī)更多更精細(xì)的內(nèi)容,來(lái)達(dá)到與百分比庫(kù)互補(bǔ)的效果,沒(méi)有一個(gè)方案可以說(shuō)自己是完美的,但我們能清晰的認(rèn)識(shí)到不同方案的優(yōu)缺點(diǎn),將它們的優(yōu)點(diǎn)相結(jié)合,才能應(yīng)付更復(fù)雜的開(kāi)發(fā)需求,產(chǎn)出最好的產(chǎn)品

友情提示: 下面要介紹的 smallestWidth 限定符屏幕適配方案,原理也同樣是按照百分比縮放布局,理論上也會(huì)存在上面所說(shuō)的 大屏手機(jī)和小屏手機(jī)顯示的內(nèi)容相同 的問(wèn)題,選擇與否請(qǐng)仔細(xì)斟酌

簡(jiǎn)介 smallestWidth 限定符適配方案

這個(gè)方案的的使用方式和我們平時(shí)在布局中引用 dimens 無(wú)異,核心點(diǎn)在于生成 dimens.xml 文件,但是已經(jīng)有大神幫我們做了這 一步

├── src/main
│   ├── res
│   ├── ├──values
│   ├── ├──values-800x480
│   ├── ├──values-860x540
│   ├── ├──values-1024x600
│   ├── ├──values-1024x768
│   ├── ├──...
│   ├── ├──values-2560x1440

如果有人還記得上面這種 寬高限定符屏幕適配方案 的話,就可以把 smallestWidth 限定符屏幕適配方案 當(dāng)成這種方案的升級(jí)版,smallestWidth 限定符屏幕適配方案 只是把 dimens.xml 文件中的值從 px 換成了 dp,原理和使用方式都是沒(méi)變的,這些在上面的文章中都有介紹,下面就直接開(kāi)始剖析原理,smallestWidth 限定符屏幕適配方案 長(zhǎng)這樣??

├── src/main
│   ├── res
│   ├── ├──values
│   ├── ├──values-sw320dp
│   ├── ├──values-sw360dp
│   ├── ├──values-sw400dp
│   ├── ├──values-sw411dp
│   ├── ├──values-sw480dp
│   ├── ├──...
│   ├── ├──values-sw600dp
│   ├── ├──values-sw640dp

原理

其實(shí) smallestWidth 限定符屏幕適配方案 的原理也很簡(jiǎn)單,開(kāi)發(fā)者先在項(xiàng)目中根據(jù)主流屏幕的 最小寬度 (smallestWidth) 生成一系列 values-sw<N>dp 文件夾 (含有 dimens.xml 文件),當(dāng)把項(xiàng)目運(yùn)行到設(shè)備上時(shí),系統(tǒng)會(huì)根據(jù)當(dāng)前設(shè)備屏幕的 最小寬度 (smallestWidth) 去匹配對(duì)應(yīng)的 values-sw<N>dp 文件夾,而對(duì)應(yīng)的 values-sw<N>dp 文件夾中的 dimens.xml 文字中的值,又是根據(jù)當(dāng)前設(shè)備屏幕的 最小寬度 (smallestWidth) 而定制的,所以一定能適配當(dāng)前設(shè)備

如果系統(tǒng)根據(jù)當(dāng)前設(shè)備屏幕的 最小寬度 (smallestWidth) 沒(méi)找到對(duì)應(yīng)的 values-sw<N>dp 文件夾,則會(huì)去尋找與之 最小寬度 (smallestWidth) 相近的 values-sw<N>dp 文件夾,系統(tǒng)只會(huì)尋找小于或等于當(dāng)前設(shè)備 最小寬度 (smallestWidth)values-sw<N>dp,這就是優(yōu)于 寬高限定符屏幕適配方案 的容錯(cuò)率,并且也可以少生成很多 values-sw<N>dp 文件夾,減輕 App 的體積

什么是 smallestWidth

smallestWidth 翻譯為中文的意思就是 最小寬度,那這個(gè) 最小寬度 是什么意思呢?

系統(tǒng)會(huì)根據(jù)當(dāng)前設(shè)備屏幕的 最小寬度 來(lái)匹配 values-sw<N>dp,為什么不是根據(jù) 寬度 來(lái)匹配,而要加上 最小 這兩個(gè)字呢?

這就要說(shuō)到,移動(dòng)設(shè)備都是允許屏幕可以旋轉(zhuǎn)的,當(dāng)屏幕旋轉(zhuǎn)時(shí),屏幕的高寬就會(huì)互換,加上 最小 這兩個(gè)字,是因?yàn)檫@個(gè)方案是不區(qū)分屏幕方向的,它只會(huì)把屏幕的高度和寬度中值最小的一方認(rèn)為是 最小寬度,這個(gè) 最小寬度 是根據(jù)屏幕來(lái)定的,是固定不變的,意思是不管您怎么旋轉(zhuǎn)屏幕,只要這個(gè)屏幕的高度大于寬度,那系統(tǒng)就只會(huì)認(rèn)定寬度的值為 最小寬度,反之如果屏幕的寬度大于高度,那系統(tǒng)就會(huì)認(rèn)定屏幕的高度的值為 最小寬度

如果想讓屏幕寬度隨著屏幕的旋轉(zhuǎn)而做出改變?cè)撛趺崔k呢?可以再根據(jù) values-w<N>dp (去掉 sw 中的 s) 生成一套資源文件

如果想?yún)^(qū)分屏幕的方向來(lái)做適配該怎么辦呢?那就只有再根據(jù) 屏幕方向限定符 生成一套資源文件咯,后綴加上 -land-port 即可,像這樣,values-sw400dp-land (最小寬度 400 dp 橫向)values-sw400dp-port (最小寬度 400 dp 縱向)

smallestWidth 的值是怎么算的

要先算出當(dāng)前設(shè)備的 smallestWidth 值我們才能知道當(dāng)前設(shè)備該匹配哪個(gè) values-sw<N>dp 文件夾

ok,還是按照上一篇文章的敘述方式,現(xiàn)在來(lái)舉栗說(shuō)明,幫助大家更好理解

我們假設(shè)設(shè)備的屏幕信息是 1920 * 1080480 dpi

根據(jù)上面的規(guī)則我們要在屏幕的高度和寬度中選擇值最小的一方作為最小寬度,1080 < 1920,明顯 1080 px 就是我們要找的 最小寬度 的值,但 最小寬度 的單位是 dp,所以我們要把 px 轉(zhuǎn)換為 dp

幫助大家再鞏固下基礎(chǔ),下面的公式一定不能再忘了!

px / density = dpDPI / 160 = density,所以最終的公式是 px / (DPI / 160) = dp

所以我們得到的 最小寬度 的值是 360 dp (1080 / (480 / 160) = 360)

現(xiàn)在我們已經(jīng)算出了當(dāng)前設(shè)備的最小寬度是 360 dp,我們曉得系統(tǒng)會(huì)根據(jù)這個(gè) 最小寬度 幫助我們匹配到 values-sw360dp 文件夾下的 dimens.xml 文件,如果項(xiàng)目中沒(méi)有 values-sw360dp 這個(gè)文件夾,系統(tǒng)才會(huì)去匹配相近的 values-sw<N>dp 文件夾

dimens.xml 文件是整個(gè)方案的核心所在,所以接下來(lái)我們?cè)賮?lái)看看 values-sw360dp 文件夾中的這個(gè) dimens.xml 是根據(jù)什么原理生成的

dimens.xml 生成原理

因?yàn)槲覀冊(cè)陧?xiàng)目布局中引用的 dimens 的實(shí)際值,來(lái)源于根據(jù)當(dāng)前設(shè)備屏幕的 最小寬度 所匹配的 values-sw<N>dp 文件夾中的 dimens.xml,所以搞清楚 dimens.xml 的生成原理,有助于我們理解 smallestWidth 限定符屏幕適配方案

說(shuō)到 dimens.xml 的生成,就要涉及到兩個(gè)因數(shù),第一個(gè)因素是 最小寬度基準(zhǔn)值,第二個(gè)因素就是您的項(xiàng)目需要適配哪些 最小寬度,通俗理解就是需要生成多少個(gè) values-sw<N>dp 文件夾

第一個(gè)因素

最小寬度基準(zhǔn)值 是什么意思呢?簡(jiǎn)單理解就是您需要把設(shè)備的屏幕寬度分為多少份,假設(shè)我們現(xiàn)在把項(xiàng)目的 最小寬度基準(zhǔn)值 定為 360,那這個(gè)方案就會(huì)理解為您想把所有設(shè)備的屏幕寬度都分為 360 份,方案會(huì)幫您在 dimens.xml 文件中生成 1360dimens 引用,比如 values-sw360dp 中的 dimens.xml 是長(zhǎng)這樣的

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <dimen name="dp_1">1dp</dimen>
    <dimen name="dp_2">2dp</dimen>
    <dimen name="dp_3">3dp</dimen>
    <dimen name="dp_4">4dp</dimen>
    <dimen name="dp_5">5dp</dimen>
    <dimen name="dp_6">6dp</dimen>
    <dimen name="dp_7">7dp</dimen>
    <dimen name="dp_8">8dp</dimen>
    <dimen name="dp_9">9dp</dimen>
    <dimen name="dp_10">10dp</dimen>
    ...
    <dimen name="dp_356">356dp</dimen>
    <dimen name="dp_357">357dp</dimen>
    <dimen name="dp_358">358dp</dimen>
    <dimen name="dp_359">359dp</dimen>
    <dimen name="dp_360">360dp</dimen>
</resources>

values-sw360dp 指的是當(dāng)前設(shè)備屏幕的 最小寬度360dp (該設(shè)備高度大于寬度,則最小寬度就是寬度,所以該設(shè)備寬度為 360dp),把屏幕寬度分為 360 份,剛好每份等于 1dp,所以每個(gè)引用都遞增 1dp,值最大的 dimens 引用 dp_360 值也是 360dp,剛好覆蓋屏幕寬度

下面再來(lái)看看將 最小寬度基準(zhǔn)值 定為 360 時(shí),values-sw400dp 中的 dimens.xml 長(zhǎng)什么樣

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <dimen name="dp_1">1.1111dp</dimen>
    <dimen name="dp_2">2.2222dp</dimen>
    <dimen name="dp_3">3.3333dp</dimen>
    <dimen name="dp_4">4.4444dp</dimen>
    <dimen name="dp_5">5.5556dp</dimen>
    <dimen name="dp_6">6.6667dp</dimen>
    <dimen name="dp_7">7.7778dp</dimen>
    <dimen name="dp_8">8.8889dp</dimen>
    <dimen name="dp_9">10.0000dp</dimen>
    <dimen name="dp_10">11.1111dp</dimen>
    ...
    <dimen name="dp_355">394.4444dp</dimen>
    <dimen name="dp_356">395.5556dp</dimen>
    <dimen name="dp_357">396.6667dp</dimen>
    <dimen name="dp_358">397.7778dp</dimen>
    <dimen name="dp_359">398.8889dp</dimen>
    <dimen name="dp_360">400.0000dp</dimen>
</resources>

values-sw400dp 指的是當(dāng)前設(shè)備屏幕的 最小寬度400dp (該設(shè)備高度大于寬度,則最小寬度就是寬度,所以該設(shè)備寬度為 400dp),把屏幕寬度同樣分為 360份,這時(shí)每份就等于 1.1111dp 了,每個(gè)引用都遞增 1.1111dp,值最大的 dimens 引用 dp_360 同樣剛好覆蓋屏幕寬度,為 400dp

通過(guò)兩個(gè) dimens.xml 文件的比較,dimens.xml 的生成原理一目了然,方案會(huì)先確定 最小寬度基準(zhǔn)值,然后將每個(gè) values-sw<N>dp 中的 dimens.xml 文件都分配與 最小寬度基準(zhǔn)值 相同的份數(shù),再根據(jù)公式 屏幕最小寬度 / 份數(shù) (最小寬度基準(zhǔn)值) 求出每份占多少 dp,保證不管在哪個(gè) values-sw<N>dp 中,份數(shù) (最小寬度基準(zhǔn)值) * 每份占的 dp 值 的結(jié)果都是剛好覆蓋屏幕寬度,所以在 份數(shù) 不變的情況下,只需要根據(jù)屏幕的寬度在不同的設(shè)備上動(dòng)態(tài)調(diào)整 每份占的 dp 值,就能完成適配

這樣就能保證不管將項(xiàng)目運(yùn)行到哪個(gè)設(shè)備上,只要當(dāng)前設(shè)備能匹配到對(duì)應(yīng)的 values-sw<N>dp 文件夾,那布局中的 dimens 引用就能根據(jù)當(dāng)前屏幕的情況進(jìn)行縮放,保證能完美適配,如果沒(méi)有匹配到對(duì)應(yīng)的 values-sw<N>dp 文件夾,也沒(méi)關(guān)系,它會(huì)去尋找與之相近的 values-sw<N>dp 文件夾,雖然在這種情況下,布局中的 dimens 引用的值可能有些許誤差,但是也能保證最大程度的完成適配

說(shuō)到這里,那大家就應(yīng)該就會(huì)明白我為什么會(huì)說(shuō) smallestWidth 限定符屏幕適配方案 的原理也同樣是按百分比進(jìn)行布局,如果在布局中,一個(gè) View 的寬度引用 dp_100,那不管運(yùn)行到哪個(gè)設(shè)備上,這個(gè) View 的寬度都是當(dāng)前設(shè)備屏幕總寬度的 360分之100,前提是項(xiàng)目提供有當(dāng)前設(shè)備屏幕對(duì)應(yīng)的 values-sw<N>dp,如果沒(méi)有對(duì)應(yīng)的 values-sw<N>dp,就會(huì)去尋找相近的 values-sw<N>dp,這時(shí)就會(huì)存在誤差了,至于誤差是大是小,這就要看您的第二個(gè)因數(shù)怎么分配了

其實(shí) smallestWidth 限定符屏幕適配方案 的原理和 今日頭條屏幕適配方案 挺像的,今日頭條屏幕適配方案 是根據(jù)屏幕的寬度或高度動(dòng)態(tài)調(diào)整每個(gè)設(shè)備的 density (每 dp 占當(dāng)前設(shè)備屏幕多少像素),而 smallestWidth 限定符屏幕適配方案 同樣是根據(jù)屏幕的寬度動(dòng)態(tài)調(diào)整每個(gè)設(shè)備 每份占的 dp 值

第二個(gè)因素

第二個(gè)因數(shù)是需要適配哪些 最小寬度?比如您想適配的 最小寬度320dp360dp400dp411dp480dp,那方案就會(huì)為您的項(xiàng)目生成 values-sw320dpvalues-sw360dpvalues-sw400dpvalues-sw411dpvalues-sw480dp 這幾個(gè)資源文件夾,像這樣??

├── src/main
│   ├── res
│   ├── ├──values
│   ├── ├──values-sw320dp
│   ├── ├──values-sw360dp
│   ├── ├──values-sw400dp
│   ├── ├──values-sw411dp
│   ├── ├──values-sw480dp

方案會(huì)為您需要適配的 最小寬度,在項(xiàng)目中生成一系列對(duì)應(yīng)的 values-sw<N>dp,在前面也說(shuō)了,如果某個(gè)設(shè)備沒(méi)有為它提供對(duì)應(yīng)的 values-sw<N>dp,那它就會(huì)去尋找相近的 values-sw<N>dp,但如果這個(gè)相近的 values-sw<N>dp 與期望的 values-sw<N>dp 差距太大,那適配效果也就會(huì)大打折扣

那是不是 values-sw<N>dp 文件夾生成的越多,覆蓋越多市面上的設(shè)備,就越好呢?

也不是,因?yàn)槊總€(gè) values-sw<N>dp 文件夾其實(shí)都會(huì)占用一定的 App 體積,values-sw<N>dp 文件夾越多,App 的體積也就會(huì)越大

所以一定要合理分配 values-sw<N>dp,以越少的 values-sw<N>dp 文件夾,覆蓋越多的機(jī)型

驗(yàn)證方案可行性

原理講完了,我們還是按照老規(guī)矩,來(lái)驗(yàn)證一下這個(gè)方案是否可行?

假設(shè)設(shè)計(jì)圖總寬度為 375 dp,一個(gè) View 在這個(gè)設(shè)計(jì)圖上的尺寸是 50dp * 50dp,這個(gè) View 的寬度占整個(gè)設(shè)計(jì)圖寬度的 13.3% (50 / 375 = 0.133)

在使用 smallestWidth 限定符屏幕適配方案 時(shí),需要提供 最小寬度基準(zhǔn)值 和需要適配哪些 最小寬度,我們就把 最小寬度基準(zhǔn)值 設(shè)置為 375 (和 設(shè)計(jì)圖 一致),這時(shí)方案就會(huì)為我們需要適配的 最小寬度 生成對(duì)應(yīng)的 values-sw<N>dp 文件夾,文件夾中的 dimens.xml 文件是由從 1375 組成的 dimens 引用,把所有設(shè)備的屏幕寬度都分為 375 份,所以在布局文件中我們應(yīng)該把這個(gè) View 的高寬都引用 dp_50

下面就來(lái)驗(yàn)證下在使用 smallestWidth 限定符屏幕適配方案 的情況下,這個(gè) View 與屏幕寬度的比例在分辨率不同的設(shè)備上是否還能保持和設(shè)計(jì)圖中的比例一致

驗(yàn)證設(shè)備 1

設(shè)備 1 的屏幕總寬度為 1080 px,屏幕總高度為 1920 pxDPI480

設(shè)備 1 的屏幕高度大于屏幕寬度,所以 設(shè)備 1最小寬度 為屏幕寬度,再根據(jù)公式 px / (DPI / 160) = dp,求出 設(shè)備 1最小寬度 的值為 360 dp (1080 / (480 / 160) = 360)

根據(jù) 設(shè)備 1最小寬度 應(yīng)該匹配的是 values-sw360dp 這個(gè)文件夾,假設(shè) values-sw360dp 文件夾及里面的 dimens.xml 已經(jīng)生成,且是按 最小寬度基準(zhǔn)值375 生成的,360 / 375 = 0.96,所以每份占的 dp 值為 0.96dimens.xml 里面的內(nèi)容是長(zhǎng)下面這樣的??

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <dimen name="dp_1">0.96dp</dimen>
    <dimen name="dp_2">1.92dp</dimen>
    <dimen name="dp_3">2.88dp</dimen>
    <dimen name="dp_4">3.84dp</dimen>
    <dimen name="dp_5">4.8dp</dimen>
    ...
    <dimen name="dp_50">48dp</dimen>
    ...
    <dimen name="dp_371">356.16dp</dimen>
    <dimen name="dp_372">357.12dp</dimen>
    <dimen name="dp_373">358.08dp</dimen>
    <dimen name="dp_374">359.04dp</dimen>
    <dimen name="dp_375">360dp</dimen>
</resources>

可以看到這個(gè) View 在布局中引用的 dp_50,最終在 values-sw360dp 中定格在了 48 dp,所以這個(gè) View設(shè)備 1 上的高寬都為 48 dp,系統(tǒng)最后會(huì)將高寬都換算成 px,根據(jù)公式 dp * (DPI / 160) = px,所以這個(gè) View 的高寬換算為 px 后等于 144 px (48 * (480 / 160) = 144)

144 / 1080 = 0.133View 的實(shí)際寬度與 屏幕總寬度 的比例和 View 在設(shè)計(jì)圖中的比例一致 (50 / 375 = 0.133),所以完成了等比例縮放

某些設(shè)備的高寬是和 設(shè)備 1 相同的,但是 DPI 可能不同,而由于 smallestWidth 限定符屏幕適配方案 并沒(méi)有像 今日頭條屏幕適配方案 一樣去自行修改 density,所以系統(tǒng)就會(huì)使用默認(rèn)的公式 DPI / 160 求出 densitydensity 又會(huì)影響到 dppx 的換算,因此 DPI 的變化,是有可能會(huì)影響到 smallestWidth 限定符屏幕適配方案

所以我們?cè)賮?lái)試試在這種特殊情況下 smallestWidth 限定符屏幕適配方案 是否也能完成適配

驗(yàn)證設(shè)備 2

設(shè)備 2 的屏幕總寬度為 1080 px,屏幕總高度為 1920 pxDPI420

設(shè)備 2 的屏幕高度大于屏幕寬度,所以 設(shè)備 2最小寬度 為屏幕寬度,再根據(jù)公式 px / (DPI / 160) = dp,求出 設(shè)備 2最小寬度 的值為 411.429 dp (1080 / (420 / 160) = 411.429)

根據(jù) 設(shè)備 2最小寬度 應(yīng)該匹配的是 values-sw411dp 這個(gè)文件夾,假設(shè) values-sw411dp 文件夾及里面的 dimens.xml 已經(jīng)生成,且是按 最小寬度基準(zhǔn)值375 生成的,411 / 375 = 1.096,所以每份占的 dp 值為 1.096dimens.xml 里面的內(nèi)容是長(zhǎng)下面這樣的??

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <dimen name="dp_1">1.096dp</dimen>
    <dimen name="dp_2">2.192dp</dimen>
    <dimen name="dp_3">3.288dp</dimen>
    <dimen name="dp_4">4.384dp</dimen>
    <dimen name="dp_5">5.48dp</dimen>
    ...
    <dimen name="dp_50">54.8dp</dimen>
    ...
    <dimen name="dp_371">406.616dp</dimen>
    <dimen name="dp_372">407.712dp</dimen>
    <dimen name="dp_373">408.808dp</dimen>
    <dimen name="dp_374">409.904dp</dimen>
    <dimen name="dp_375">411dp</dimen>
</resources>

可以看到這個(gè) View 在布局中引用的 dp_50,最終在 values-sw411dp 中定格在了 54.8dp,所以這個(gè) View設(shè)備 2 上的高寬都為 54.8 dp,系統(tǒng)最后會(huì)將高寬都換算成 px,根據(jù)公式 dp * (DPI / 160) = px,所以這個(gè) View 的高寬換算為 px 后等于 143.85 px (54.8 * (420 / 160) = 143.85)

143.85 / 1080 = 0.133View 的實(shí)際寬度與 屏幕總寬度 的比例和 View 在設(shè)計(jì)圖中的比例一致 (50 / 375 = 0.133),所以完成了等比例縮放

雖然 View設(shè)備 2 上的高寬是 143.85 px,比 設(shè)備 1144 px 少了 0.15 px,但是誤差非常小,整體的比例并沒(méi)有發(fā)生太大的變化,是完全可以接受的

這個(gè)誤差是怎么引起的呢,因?yàn)?設(shè)備 2最小寬度 的實(shí)際值是 411.429 dp,但是匹配的 values-sw411dp 舍去了小數(shù)點(diǎn)后面的位數(shù) (切記!系統(tǒng)會(huì)去尋找小于或等于 411.429 dp 的 values-sw<N>dp,所以 values-sw412dp 這個(gè)文件夾,設(shè)備 2 是匹配不了的),所以才存在了一定的誤差,因此上面介紹的第二個(gè)因數(shù)是非常重要的,這直接決定誤差是大還是小

可以看到即使在高寬一樣但 DPI 不一樣的設(shè)備上,smallestWidth 限定符屏幕適配方案 也能完成等比例適配,證明這個(gè)方案是可行的,如果大家還心存疑慮,也可以再試試其他分辨率的設(shè)備,其實(shí)到最后得出的比例都是在 0.133 左右,唯一的變數(shù)就是第二個(gè)因數(shù),如果您生成的 values-sw<N>dp 與設(shè)備實(shí)際的 最小寬度 差別不大,那誤差也就在能接受的范圍內(nèi),如果差別很大,那就直接 GG

優(yōu)點(diǎn)

  1. 非常穩(wěn)定,極低概率出現(xiàn)意外

  2. 不會(huì)有任何性能的損耗

  3. 適配范圍可自由控制,不會(huì)影響其他三方庫(kù)

  4. 在插件的配合下,學(xué)習(xí)成本低

缺點(diǎn)

  1. 在布局中引用 dimens 的方式,雖然學(xué)習(xí)成本低,但是在日常維護(hù)修改時(shí)較麻煩

  2. 侵入性高,如果項(xiàng)目想切換為其他屏幕適配方案,因?yàn)槊總€(gè) Layout 文件中都存在有大量 dimens 的引用,這時(shí)修改起來(lái)工作量非常巨大,切換成本非常高昂

  3. 無(wú)法覆蓋全部機(jī)型,想覆蓋更多機(jī)型的做法就是生成更多的資源文件,但這樣會(huì)增加 App 體積,在沒(méi)有覆蓋的機(jī)型上還會(huì)出現(xiàn)一定的誤差,所以有時(shí)需要在適配效果和占用空間上做一些抉擇

  4. 如果想使用 sp,也需要生成一系列的 dimens,導(dǎo)致再次增加 App 的體積

  5. 不能自動(dòng)支持橫豎屏切換時(shí)的適配,如上文所說(shuō),如果想自動(dòng)支持橫豎屏切換時(shí)的適配,需要使用 values-w<N>dp屏幕方向限定符 再生成一套資源文件,這樣又會(huì)再次增加 App 的體積

  6. 不能以高度為基準(zhǔn)進(jìn)行適配,考慮到這個(gè)方案的名字本身就叫 最小寬度限定符適配方案,所以在使用這個(gè)方案之前就應(yīng)該要知道這個(gè)方案只能以寬度為基準(zhǔn)進(jìn)行適配,為什么現(xiàn)在的屏幕適配方案只能以高度或?qū)挾绕渲械囊粋€(gè)作為基準(zhǔn)進(jìn)行適配,請(qǐng)看 這里

使用中的問(wèn)題

這時(shí)有人就會(huì)問(wèn)了,設(shè)計(jì)師給的設(shè)計(jì)圖只標(biāo)注了 px,使用這個(gè)方案時(shí),那不是還要先將 px 換算成 dp

其實(shí)也可以不用換算的,那這是什么騷操作呢?

很簡(jiǎn)單,你把設(shè)計(jì)圖的 px 總寬度設(shè)置成 最小寬度基準(zhǔn)值 就可以了,還是以前面驗(yàn)證可行性的例子

我們?cè)谇懊骝?yàn)證可行性時(shí)把 最小寬度基準(zhǔn)值 設(shè)置成了 375,為什么是 375 呢?因?yàn)樵O(shè)計(jì)圖的總寬度為 375 dp,如果換算成 px,總寬度就是 750 px,我們這時(shí)把 最小寬度基準(zhǔn)值 設(shè)置成 750,然后看看 values-sw360dp 中的 dimens.xml 長(zhǎng)什么樣??

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <dimen name="px_1">0.48dp</dimen>
    <dimen name="px_2">0.96dp</dimen>
    <dimen name="px_3">1.44dp</dimen>
    <dimen name="px_4">1.92dp</dimen>
    <dimen name="px_5">2.4dp</dimen>
    ...
    <dimen name="px_50">24dp</dimen>
    ...
    <dimen name="px_100">48dp</dimen>
    ...
    <dimen name="px_746">358.08dp</dimen>
    <dimen name="px_747">358.56dp</dimen>
    <dimen name="px_748">359.04dp</dimen>
    <dimen name="px_749">359.52dp</dimen>
    <dimen name="px_750">360dp</dimen>
</resources>

360 dp 被分成了 750 份,相比之前的 375 份,現(xiàn)在 每份占的 dp 值 正好減少了一半,還記得在驗(yàn)證可行性的例子中那個(gè) View 的尺寸是多少嗎?50dp * 50dp,如果設(shè)計(jì)圖只標(biāo)注 px,那這個(gè) View 在設(shè)計(jì)圖上的的尺寸應(yīng)該是 100px * 100px,那我們直接根據(jù)設(shè)計(jì)圖上標(biāo)注的 px,想都不用想直接在布局中引用 px_100 就可以了,因?yàn)樵?375 份時(shí)的 dp_50 剛好等于 750 份時(shí)的 px_100 (值都是 48 dp),所以這時(shí)的適配效果和之前驗(yàn)證可行性時(shí)的適配效果沒(méi)有任何區(qū)別

看懂了嗎?直接將 最小寬度基準(zhǔn)值 和布局中的引用都以 px 作為單位就可以直接填寫(xiě)設(shè)計(jì)圖上標(biāo)注的 px

總結(jié)

關(guān)于文中所列出的優(yōu)缺點(diǎn),列出的缺點(diǎn)數(shù)量確實(shí)比列出的優(yōu)點(diǎn)數(shù)量多,但 缺點(diǎn) 3缺點(diǎn) 4缺點(diǎn) 5 其實(shí)都可以歸納于 占用 App 體積 這一個(gè)缺點(diǎn),因?yàn)樗麄兌伎梢酝ㄟ^(guò)增加資源文件來(lái)解決問(wèn)題,而 缺點(diǎn) 6 則是這個(gè)方案的特色,只能以寬度為基準(zhǔn)進(jìn)行適配,這個(gè)從這個(gè)方案的名字就能看出

請(qǐng)大家千萬(wàn)不要曲解文章的意思,不要只是單純的對(duì)比優(yōu)缺點(diǎn)的數(shù)量,缺點(diǎn)的數(shù)量大于優(yōu)點(diǎn)的數(shù)量就一定是這個(gè)方案不行?沒(méi)有一個(gè)方案是完美的,每個(gè)人的需求也都不一樣,作為一篇科普類文章我只可能把這個(gè)方案描述得盡可能的全面

這個(gè)方案能給你帶來(lái)什么,不能給你帶來(lái)什么,我必須客觀的描述清楚,這樣才有助你做出決定,你應(yīng)該注重的是在這些優(yōu)缺點(diǎn)里什么是我能接受的,什么是我不能接受的,是否能為了某些優(yōu)點(diǎn)做出某些妥協(xié),而不只是單純的去看數(shù)量,這樣毫無(wú)意義,有些人就是覺(jué)得穩(wěn)定性最重要,其他的都可以做出妥協(xié),那其他缺點(diǎn)對(duì)于他來(lái)說(shuō)都是無(wú)所謂的

好了,這個(gè)系列的第二篇文章講完了,這篇文章也是按照上篇文章的優(yōu)良傳統(tǒng),寫(xiě)的非常詳細(xì),哪怕是新手我相信也應(yīng)該能看懂,為什么這么多人都不知道自己該選擇什么樣的方案,就是因?yàn)樽约憾紱](méi)搞懂這些方案的原理,懂了原理過(guò)后才知道這些方案是否是自己想要的

接下來(lái)的第三篇文章會(huì)詳細(xì)講解兩個(gè)方案的深入對(duì)比以及該如何選擇,并剖析我根據(jù) 今日頭條屏幕適配方案 優(yōu)化的屏幕適配框架 AndroidAutoSize 的原理,敬請(qǐng)期待

如果大家想使用 smallestWidth 限定符屏幕適配方案,可以參考 這篇文章,里面提供有自動(dòng)生成資源文件的插件和 Demo,由于我并沒(méi)有在項(xiàng)目中使用 smallestWidth 限定符屏幕適配方案,所以如果在文章中有遺漏的知識(shí)點(diǎn)請(qǐng)諒解以及補(bǔ)充,感謝!

公眾號(hào)

掃碼關(guān)注我的公眾號(hào) JessYan,一起學(xué)習(xí)進(jìn)步,如果框架有更新,我也會(huì)在公眾號(hào)上第一時(shí)間通知大家

公眾號(hào)

以下是 騷年你的屏幕適配方式該升級(jí)了! 系列文章,歡迎轉(zhuǎn)發(fā)以及分享:


Hello 我叫 JessYan,如果您喜歡我的文章,可以在以下平臺(tái)關(guān)注我

-- The end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

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