Android UI適配方案

大綱

  1. 使用dp而不是px
  2. 盡量使用自動(dòng)適配布局,而不要指定分辨率
  3. 使用寬高限定符
    1. values-1080x1920匈挖,以1080P為基準(zhǔn)計(jì)算每種常見分辨率對(duì)應(yīng)的尺寸儡循。
    2. 需要盡可能全的添加各種設(shè)備的分辨率(有工具)
    3. 容錯(cuò)性不足择膝,如果設(shè)備分辨率不能精確匹配對(duì)應(yīng)限定符肴捉,會(huì)默認(rèn)使用統(tǒng)一默認(rèn)的dimens
  4. 第三方自動(dòng)適配UI框架
    1. 原理:自定義RelativeLayout齿穗,在onMeasure中對(duì)控件分辨率做變換
    2. 第三方框架饺律,維護(hù)性很成問題
    3. 一些自定義View蓝晒,處理比較麻煩
  5. 最小寬度限定符芝薇,類似寬高限定符
    1. values-sw240dp洛二,同樣以某一dp寬度為基準(zhǔn)計(jì)算其他寬度dp的值
    2. values-sw360dp晾嘶、values-sw480dp
    3. 相比寬高限定符垒迂,最小寬度限定符不進(jìn)行精確匹配妒蛇,會(huì)遵循就近原則楷拳,可以較好的解決容錯(cuò)問題欢揖。
    4. 如:設(shè)備寬364dp她混,系統(tǒng)會(huì)自動(dòng)就近配置values-sw360dp下的dimens泊碑,顯示效果相差不會(huì)很大
  6. 今日頭條——修改density值
    1. 原理:px = dp x (dpi/160) = dp x density
    2. 既然如此蛾狗,將density
    3. 需要UI出設(shè)計(jì)圖時(shí)以統(tǒng)一的dp為基準(zhǔn)
    4. https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA

基本概念

  • 像素——px
  • 密度獨(dú)立像素——dp或dip
  • 像素密度——dpi沉桌,單位面積內(nèi)的像素?cái)?shù)。
    • 軟件系統(tǒng)的概念佃扼。
    • 在系統(tǒng)出廠時(shí)兼耀,配置文件中的固定值瘤运。
    • 通常的取值有:160匠题、240韭山、360钱磅、480等。
    • 不同于物理概念上的屏幕密度ppi年柠,如ppi為415彪杉、430和470時(shí)派近,dpi可能會(huì)統(tǒng)一設(shè)置為480。
  • density——當(dāng)dpi=160時(shí)侯嘀,1px = 1pd,此時(shí)denstiy的值為1戒幔,dpi=240時(shí)土童,1.5px = 1dp,density的值為1.5献汗。
  • 上述值的關(guān)系:
    • denstiy = dpi / 160;
    • px = dp x density = dp x (dpi / 160)

Android設(shè)備的碎片化極為嚴(yán)重楚午,各種尺寸和分辨率的設(shè)備無比繁多矾柜。使得在Android開發(fā)中就谜,UI適配變成了開發(fā)過程中極為重要的一步丧荐。為此Google提出了密度獨(dú)立像素dip或dp的概率,旨在更友好的處理Android UI適配問題。

但是效果嘛窟却,只能說差強(qiáng)人意夸赫,可以解決大部分的業(yè)務(wù)場(chǎng)景咖城,但是剩下的個(gè)別情況就搞死人了呼奢,原因在于Android設(shè)備碎片化實(shí)在太嚴(yán)重了握础,存在各種分辨率和dpi的設(shè)備禀综。

比如兩臺(tái)設(shè)備A和B定枷,分辨率是1920x1080欠窒,dpi分別為420和480岖妄,在布局中編寫一個(gè)100dp寬的ImageView衣吠,按照上面的公式ImageView的顯示寬度分別為:100dp x 420 / 160 = 262.5100dp x 480 / 160 = 300壤靶,ImageView在B設(shè)備上明顯顯示要大一些忧换。差異可能還不明顯向拆,我們把寬度改為360dp呢浓恳,A設(shè)備顯示寬度為:948px梢夯,B設(shè)備顯示寬度為:1080px颂砸。這就扯淡了,一個(gè)寬度填充滿屏幕勤篮,一個(gè)不滿碰缔。這種情況肯定是需要開發(fā)來背鍋解決的手负。

適配方案

雖然上面提到了使用dp無法解決全部業(yè)務(wù)場(chǎng)景姑尺,但是相對(duì)于直接使用px已經(jīng)可以解決大部分場(chǎng)景下的適配問題了竟终。

所以UI適配的第一條就是:

1. 使用dp代替px來編寫布局。

又因?yàn)樯厦鏌o法適配的個(gè)別場(chǎng)景切蟋,所以UI適配的第二條是:

2.盡量使用自動(dòng)適配布局统捶,而不要指定分辨率

這一條也很好理解,盡量使用ConstraintLayout約束布局和LinearLayout等父布局柄粹,不要寫死分辨率喘鸟,比如上面的例子如果使用match_parent而不是360dp,也可以避免出現(xiàn)顯示不一致問題(但是僅限于上列)驻右。

限定符

Google同樣意識(shí)到dp滿足所以業(yè)務(wù)場(chǎng)景的需要什黑,所以提供了寬度限定符的概念堪夭。

雖然您的布局應(yīng)始終通過拉伸其視圖內(nèi)部和周圍的空間來應(yīng)對(duì)不同的屏幕尺寸,但這可能無法針對(duì)每種屏幕尺寸提供最佳用戶體驗(yàn)橘蜜。例如,您為手機(jī)設(shè)計(jì)的界面或許無法在平板電腦上提供良好的體驗(yàn)。因此,您的應(yīng)用還應(yīng)提供備用布局資源克蚂,以針對(duì)特定屏幕尺寸優(yōu)化界面設(shè)計(jì)悉罕。

最小寬度限定符

使用“最小寬度”屏幕尺寸限定符类早,您可以為具有最小寬度(以密度無關(guān)像素 dp 或 dip 為度量單位)的屏幕提供備用布局逆日。

通過將屏幕尺寸描述為密度無關(guān)像素的度量值,Android 允許您創(chuàng)建專為非常具體的屏幕尺寸而設(shè)計(jì)的布局坪圾,同時(shí)讓您不必對(duì)不同的像素密度有任何擔(dān)心已日。

通俗一點(diǎn)翻譯就是:可用通過xxxx-swXXXdp的方式定義一些最小限定符的資源文件,比如:values-sw400dp护奈、values-sw600dp,系統(tǒng)會(huì)自動(dòng)匹配如屏幕寬度相近資源文件夾。

我們?cè)賮砜瓷厦娴睦觾膳_(tái)設(shè)備A和B檐晕,分辨率是1920x1080篡石,dpi分別為360和400。我們簡(jiǎn)化下問題比如設(shè)計(jì)圖給的是1920x1080 360dpi湿诊,包含一個(gè)22.5px * 22.5px = 10dp * 10dp的圖片朗和。按經(jīng)驗(yàn)布局應(yīng)該如下編寫:

<ImageView
    android:id="@+id/img_iv"
    android:layout_width="10dp"
    android:layout_height="10dp"
    android:background="@mipmap/ic_launcher"/>

在不同設(shè)備上運(yùn)行的結(jié)果:

  • 1280 x 720 240dpi的設(shè)備憔儿,圖片顯示為15px * 15px;
  • 1920 x1080 360dpi的A設(shè)備拾氓,圖片顯示為22.5px * 22.5px;
  • 1920 x1080 400dpi的B設(shè)備,圖片顯示為25px * 25px;

可以看到B設(shè)備圖片顯示是有問題的,為了解決這個(gè)問題拒课,我們使用最小寬度限定符定義兩個(gè)資源文件夾:values-sw360dp和values-sw400dp。

在values-sw360dp中添加dimen.xml內(nèi)容如下:

<?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_360">360dp</dimen>
    <!-- 因?yàn)樵O(shè)計(jì)圖是360dpi,所以控件尺寸通常不會(huì)超過360dp,定義最大360dp的值足夠使用 -->
</resources>

在values-sw420dp中添加dimen.xml,文件中的dimen值很容易換算出來:在360dpi中dp_1 = 1dp,那么在400dpi中dp_1 = 360 / 400 = 0.9dp,文件內(nèi)容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="dp_1">0.9dp</dimen>
    <dimen name="dp_2">1.8dp</dimen>
    <dimen name="dp_3">2.7dp</dimen>
    <dimen name="dp_4">3.6dp</dimen>
    <dimen name="dp_5">4.5dp</dimen>
    <dimen name="dp_6">5.4dp</dimen>
    <dimen name="dp_7">6.3dp</dimen>
    <!-- 省略其他值 -->
</resources>

注意要在values文件夾下添加默認(rèn)dimen.xml沼撕,文件內(nèi)容與values-sw360dp中添加dimen.xml一致(因?yàn)樵O(shè)計(jì)圖恰好是360dpi的)笼沥。

布局中的ImageView自然要改寫為:

<ImageView
    android:id="@+id/img_iv"
    android:layout_width="@dimen/dp_10"
    android:layout_height="@dimen/dp_10"
    android:background="@mipmap/ic_launcher"/>

我們?cè)賮砜匆幌虏煌O(shè)備運(yùn)行結(jié)果:

  • 1280 x 720 240dpi的設(shè)備,未匹配到限定符使用values中的dimen鉴裹,dp_10 = 10dp, px = 10 * 240 / 160 = 15px总处,圖片顯示尺寸為15px * 15px荸频。
  • 1920 x1080 360dpi的A設(shè)備遇绞,匹配到sw360dp限定符褐健,dp_10 = 10dp, px = 10 * 360 / 160 = 20px,圖片顯示尺寸為22.5px * 22.5px坐梯。
  • 1920 x1080 400dpi的B設(shè)備蹋辅,匹配到sw420dp限定符褒傅,dp_10 = 9dp, px = 9 * 400 / 160 = 20px碌尔,圖片顯示尺寸為22.5px * 22.5px叹坦。

完美的解決了設(shè)備A和B的顯示問題测蹲,所以UI適配的第三條是:

3. 使用最辛鹜凇(可用)寬度限定符,解決同樣分辨率不同dpi的設(shè)備適配問題妙同。

這種方案看似完美芒涡,但是也有一些隱含的問題:此方案只能解決同樣分辨率不同dpi設(shè)備的適配問題:

  • 一旦出現(xiàn)不同分辨率相同dpi的情況就無效了(當(dāng)然這種情況的可能性不高)旱幼。
  • 以上舉例只是基于1920x1080這一種分辨率為例說明,試想一下如果1280x720的設(shè)備存在240dpi和280dpi的情況呢弛车?我們只能針對(duì)特殊情況適配處理,無法解決全部場(chǎng)景適配問題。

寬高限定符

類似于上面說的最小寬度限定符浩姥,但是需要精確指定要匹配的設(shè)備寬高兜挨,values-1920x1080柒桑、values-1280x720等。配置與使用方式也與上面類似净响,如設(shè)計(jì)圖尺寸為1920x1080 360dpi,那么只需要以1920x1080為基準(zhǔn)計(jì)算所有分辨率對(duì)應(yīng)的尺寸就可以了刁卜,布局編寫時(shí)按照給的尺寸一一對(duì)應(yīng)就可以蛔趴,比如:給出的ImageView是20px*20px的,那在布局中同樣指定width和height為@dimen/dp_20就可以了例朱。

values-1920x1080中dimens.xml如下:

<resources>
    <dimen name="dp_1">1px</dimen>
    <dimen name="dp_2">2px</dimen>
    <dimen name="dp_3">3px</dimen>
    <dimen name="dp_4">4px</dimen>
    <dimen name="dp_5">5px</dimen>
    <dimen name="dp_6">6px</dimen>
    <dimen name="dp_7">7px</dimen>
    <dimen name="dp_8">8px</dimen>
    <dimen name="dp_9">9px</dimen>
    <!-- 省略其他 -->
    <dimen name="dp_1920">1920px</dimen>
</resources>

values-1280x720中dimens.xml換算為:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="dp_1">0.66px</dimen>
    <dimen name="dp_2">1.33px</dimen>
    <dimen name="dp_3">2.0px</dimen>
    <dimen name="dp_4">2.66px</dimen>
    <dimen name="dp_5">3.33px</dimen>
    <dimen name="dp_6">4.0px</dimen>
    <dimen name="dp_7">4.66px</dimen>
    <!-- 省略其他 -->
</resources>

同樣需要在values添加默認(rèn)尺寸dimen.xml孝情,內(nèi)容同基準(zhǔn)分辨率文件鱼蝉。

因?yàn)椴皇撬性O(shè)備屏幕都是16:9的,也可以按照寬高拆分成兩個(gè)dimens.xml文件dimen_x.xml和dimen_y.xml箫荡,按照寬高:1920x1080分別換算得到x和y的值魁亦,但是頁面設(shè)計(jì)通常是豎屏可滑動(dòng)的,所以對(duì)高度不敏感菲茬,只需要根據(jù)一個(gè)維度計(jì)算統(tǒng)一值就可以了吉挣。

以上計(jì)算方式比較簡(jiǎn)單了,不需要自己編寫換算可以通過代碼工具或者自己寫個(gè)類實(shí)現(xiàn)婉弹。(網(wǎng)上有好多睬魂,找一下應(yīng)該可以找到)。

理論上只要盡可能多的枚舉所有設(shè)備分辨率镀赌,就可以完美的解決屏幕適配問題氯哮,所以UI適配的第四條是:

4.使用寬高限定符,精確匹配屏幕分辨率商佛。

這種方案已經(jīng)近乎完美了喉钢,一度成為比較熱門的解決方案,也有很多團(tuán)隊(duì)使用過此方案良姆。但是之前也說過Android設(shè)備的碎片化太嚴(yán)重了肠虽,綜合考慮基本不可能在項(xiàng)目中枚舉所有的屏幕尺寸進(jìn)行適配,如果設(shè)備沒有匹配到對(duì)應(yīng)尺寸會(huì)使用values下的默認(rèn)尺寸文件玛追,可能會(huì)出現(xiàn)嚴(yán)重的UI適配問題税课。

但是不可否認(rèn)此種方案實(shí)現(xiàn)簡(jiǎn)單,對(duì)于編寫布局也很友好(直接填入設(shè)計(jì)圖的尺寸值就行痊剖,不需要換算)韩玩,可以解決絕大多數(shù)的設(shè)備適配問題,是一種很友好的解決方案陆馁。

第三方UI適配框架

有很多第三方庫的解決方案找颓,是從ViewGroup入手的,要么重寫常用的如:RelativeLayout叮贩、LinearLayout和FrameLayout等在控件內(nèi)部做轉(zhuǎn)換來適配不同尺寸的設(shè)備击狮,要么提供新的Layout如:Google的PercentLayout布局。但是這些方案基本都不在維護(hù)了益老,這里就不詳細(xì)展開了帘不,感興趣的可以自行搜索了解。

UI適配的第五條是:

5. 使用第三方自適配框架杨箭,解決UI適配問題寞焙。

感興趣的可以參考以下文檔:

其他適配方案

參考字節(jié)的實(shí)現(xiàn)方案:

一種極低成本的Android屏幕適配方式

這篇文章著實(shí)屬于拾人牙慧了,起因是因?yàn)榭吹搅诉@篇博客Android 目前最穩(wěn)定和高效的UI適配方案。所以想著確實(shí)應(yīng)該把這部分知識(shí)梳理一下捣郊,所以寫了這篇文檔加了一些自己的里面辽狈,主要也是為了梳理知識(shí)點(diǎn)加深理解。

文中列舉的幾種UI適配方案呛牲,沒有嚴(yán)格的優(yōu)劣之分刮萌,可以根據(jù)自己的業(yè)務(wù)需求選擇,也可以選擇幾種搭配使用娘扩,比如筆者目前主要做智能電視(盒子)的應(yīng)用開發(fā)着茸,Android電視不同于手機(jī),碎片化沒有那么嚴(yán)重琐旁,電視分辨率種類屈指可數(shù)涮阔,所以在日常項(xiàng)目中基本選擇使用寬高限定符的方案進(jìn)行適配,效果也是極好的灰殴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末敬特,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子牺陶,更是在濱河造成了極大的恐慌伟阔,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掰伸,死亡現(xiàn)場(chǎng)離奇詭異皱炉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)狮鸭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門合搅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人怕篷,你說我怎么就攤上這事⌒镏纾” “怎么了廊谓?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)麻削。 經(jīng)常有香客問我蒸痹,道長(zhǎng),這世上最難降的妖魔是什么呛哟? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任叠荠,我火速辦了婚禮,結(jié)果婚禮上扫责,老公的妹妹穿的比我還像新娘榛鼎。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布者娱。 她就那樣靜靜地躺著抡笼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪黄鳍。 梳的紋絲不亂的頭發(fā)上推姻,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音框沟,去河邊找鬼藏古。 笑死,一個(gè)胖子當(dāng)著我的面吹牛忍燥,可吹牛的內(nèi)容都是我干的拧晕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼灾前,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼防症!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哎甲,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤蔫敲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后炭玫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奈嘿,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年吞加,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了裙犹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衔憨,死狀恐怖叶圃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情践图,我是刑警寧澤掺冠,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站码党,受9級(jí)特大地震影響德崭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜揖盘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一眉厨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧兽狭,春花似錦憾股、人聲如沸鹿蜀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耻姥。三九已至,卻和暖如春有咨,著一層夾襖步出監(jiān)牢的瞬間琐簇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工座享, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婉商,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓渣叛,卻偏偏與公主長(zhǎng)得像丈秩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子淳衙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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