Android 目前最穩定和高效的UI適配方案

來源:互聯網
上載者:User

標籤:用戶端   其他   view   詳細   小夥伴   目錄   des   配置   插入   

Android系統發布十多年以來,關於Android的UI的適配一直是開發環節中最重要的問題,但是我看到還是有很多小夥伴對Android適配方案不瞭解。剛好,近期準備對糗事百科Android用戶端設計一套UI尺寸適配方案,可以和小夥伴們詳細的聊一聊這個問題。
Android適配最核心的問題有兩個,其一,就是適配的效率,即把設計圖轉化為App介面的過程是否高效,其二如何保證實現UI介面在不同尺寸和解析度的手機中UI的一致性。這兩個問題都很重要,一個是保證我們開發的高效,一個是保證我們適配的成效;今天我們就這兩個核心的問題來聊一聊Android的適配方案。

首先,大家都知道,在標識尺寸的時候,Android並不推薦我們使用px這個真實像素單位,因為不同的手機之間,解析度是不同的,比如一個96*96像素的控制項在解析度越來越高的手機上會在整體UI中看起來越來越小。

出現類似於這樣這樣,整體的布局效果可能會變形,所以px這個單位在布局檔案中是不推薦的。
dp直接適配
針對這種情況,Android推薦使用dp作為尺寸單位來適配UI.
那麼什麼是dp?dp指的是裝置獨立像素,以dp為尺寸單位的控制項,在不同解析度和尺寸的手機上代表了不同的真實像素,比如在解析度較低的手機中,可能1dp=1px,而在解析度較高的手機中,可能1dp=2px,這樣的話,一個96*96dp的控制項,在不同的手機中就能表現出差不多的大小了。那麼這個dp是如何計算的呢? 我們都知道一個公式: px = dp(dpi/160) 系統都是通過這個來判斷px和dp的數學關係,
那麼這裡又出現了一個問題,dpi是什麼呢?
dpi是像素密度,指的是在系統軟體上指定的單位尺寸的像素數量,它往往是寫在系統出廠設定檔的一個固定值。
我為什麼要強調它是軟體系統上的概念?因為大家買手機的時候,往往會聽到另一個叫ppi的參數,這個在手機螢幕中指的也是像素密度,但是這個是物理上的概念,它是客觀存在的不會改變。dpi是軟體參考了物理像素密度後,人為指定的一個值,這樣保證了某一個區間內的物理像素密度在軟體上都使用同一個值。這樣會有利於我們的UI適配。
比如,幾部相同解析度不同尺寸的手機的ppi可能分別是是430,440,450,那麼在Android系統中,可能dpi會全部指定為480.這樣的話,dpi/160就會是一個相對固定的數值,這樣就能保證相同解析度下不同尺寸的手機表現一致。
而在不同解析度下,dpi將會不同,比如:

...
1080720
1920
1080

dpi
320
480

dpi/160
2
3

根據上面的表格,我們可以發現,720P,和1080P的手機,dpi是不同的,這也就意味著,不同的解析度中,1dp對應不同數量的px(720P中,1dp=2px,1080P中1dp=3px),這就實現了,當我們使用dp來定義一個控制項大小的時候,他在不同的手機裡表現出相應大小的像素值。

我們可以說,通過dp加上調適型配置和weight比例布局可以基本解決不同手機上適配的問題,這基本是最原始的Android適配方案。
這種方式存在兩個小問題,第一,這隻能保證我們寫出來的介面適配絕大部分手機,部分手機仍然需要單獨適配,為什麼dp只解決了90%的適配問題,因為並不是所有的1080P的手機dpi都是480,比如Google 的Pixel2(19201080)的dpi是420,也就是說,在Pixel2中,1dp=2.625px,這樣會導致相同解析度的手機中,這樣,一個100dp100dp的控制項,在一般的1080P手機上,可能都是300px,而Pixel 2 中 ,就只有262.5px,這樣控制項的實際大小會有所不同。
為了更形象的展示,假設我們在布局檔案中把一個ImageView的寬度設定為360dp,那麼在下面兩張圖中表現是不一樣的:
圖一是1080P,480dpi的手機,圖二是1080P,420dpi的手機

從上面的布局中可以看到,同樣是1080P的手機,差異是比較明顯的。在這種情況下,我們的UI可能需要做一些微調甚至單獨適配。
第二個問題,這種方式無法快速高效的把設計師的設計稿實現到布局代碼中,通過dp直接適配,我們只能讓UI基本適配不同的手機,但是在設計圖和UI代碼之間的鴻溝,dp是無法解決的,因為dp不是真實像素。而且,設計稿的寬高往往和Android的手機真實寬高差別極大,以我們的設計稿為例,設計稿的寬高是375px750px,而真實手機可能普遍是10801920,
那麼在日常開發中我們是怎麼跨過這個鴻溝的呢?基本都是通過百分比啊,或者通過估算,或者設定一個規範值等等。總之,當我們拿到設計稿的時候,設計稿的ImageView是128px128px,當我們在編寫layout檔案的時候,卻不能直接寫成128dp128dp。在把設計稿向UI代碼轉換的過程中,我們需要耗費相當的精力去轉換尺寸,這會極大的降低我們的生產力,拉低開發效率。
寬高限定符適配
為了高效的實現UI開發,出現了新的適配方案,我把它稱作寬高限定符適配。簡單說,就是窮舉市面上所有的Android手機的寬高像素值:

設定一個基準的解析度,其他解析度都根據這個基準解析度來計算,在不同的尺寸檔案夾內部,根據該尺寸編寫對應的dimens檔案。
比如以480x320為基準解析度

寬度為320,將任何解析度的寬度整分為320份,取值為x1-x320
高度為480,將任何解析度的高度整分為480份,取值為y1-y480

那麼對於800480的解析度的dimens檔案來說,
x1=(480/320)
1=1.5px
x2=(480/320)*2=3px
...

這個時候,如果我們的UI設計介面使用的就是基準解析度,那麼我們就可以按照設計稿上的尺寸填寫相對應的dimens引用了,而當APP運行在不同解析度的手機中時,這些系統會根據這些dimens引用去該解析度的檔案夾下面尋找對應的值。這樣基本解決了我們的適配問題,而且極大的提升了我們UI開發的效率,
但是這個方案有一個致命的缺陷,那就是需要精準命中才能適配,比如1920x1080的手機就一定要找到1920x1080的限定符,否則就只能用統一的預設的dimens檔案了。而使用預設的尺寸的話,UI就很可能變形,簡單說,就是容錯機制很差。
不過這個方案有一些團隊用過,我們可以認為它是一個比較成熟有效方案了。
UI適配架構(已經停止維護)
鴻洋大佬的適配方案的項目也來自於寬高限定符方案的啟發。
使用方法也很簡單:
第一步:
在你的項目的AndroidManifest中註明你的設計稿的尺寸。
<meta-data android:name="design_width" android:value="768">
</meta-data>
<meta-data android:name="design_height" android:value="1280">
</meta-data>
第二步:
讓你的Activity繼承自AutoLayoutActivity.
然後我們就可以直接在布局檔案裡面使用具體的像素值了,比如,設計稿上是96*96,那麼我們可以直接寫96px,APP運行時,架構會協助我們根據不同手機的具體尺寸按比例伸縮。
這可以說是一個極好的方案,因為它在寬高限定符適配的基礎上更進一步,並且解決了容錯機制的問題,可以說完美的達成了開發高效和適配精準的兩個要求。
但是我們能夠想到,因為架構要在運行時會在onMeasure裡面做變換,我們自訂的控制項可能會被影響或限制,可能有些特定的控制項,需要單獨適配,這裡面可能存在的暗坑是不可預見的,還有一個比較重要的問題,那就是整個適配工作是有架構完成的,而不是系統完成的,一旦使用這個架構,未來一旦遇到很難解決的問題,替換起來是非常麻煩的,而且項目一旦停止維護,後續的升級就只能靠你自己了,這種代價團隊能否承受?當然,它已經停止維護了。
不過僅僅就技術方案而言,不可否認,這是一個很好的開源項目。
小結
討論的上述幾種適配方案都是可以實際用於開發中的比較成熟的方案,而且確實有很多開發人員正在使用。不過由於他們各自都存在一些缺陷,所以我們使用了上述方案後還需要花費額外的精力著手解決這些可能存在的缺陷。
那麼,是否存在一種相對比較完美,沒有明顯的缺陷的方案呢?
smallestWidth適配
smallestWidth適配,或者叫sw限定符適配。指的是Android會識別螢幕可用高度和寬度的最小尺寸的dp值(其實就是手機的寬度值),然後根據識別到的結果去資源檔中尋找對應限定符的檔案夾下的資源檔。
這種機制和上文提到的寬高限定符適配原理上是一樣的,都是系統通過特定的規則來選擇對應的檔案。
舉個例子,小米5的dpi是480,橫向像素是1080px,根據px=dp(dpi/160),橫向的dp值是1080/(480/160),也就是360dp,系統就會去尋找是否存在value-sw360dp的檔案夾以及對應的資源檔。

smallestWidth限定符適配和寬高限定符適配最大的區別在於,前者有很好的容錯機制,如果沒有value-sw360dp檔案夾,系統會向下尋找,比如離360dp最近的只有value-sw350dp,那麼Android就會選擇value-sw350dp檔案夾下面的資源檔。這個特性就完美的解決了上文提到的寬高限定符的容錯問題。
這套方案是上述幾種方案中最接近完美的方案。
首先,從開發效率上,它不遜色於上述任意一種方案。根據固定的放縮比例,我們基本可以按照UI設計的尺寸不假思索的填寫對應的dimens引用。
我們還有以375個像素寬度的設計稿為例,在values-sw360dp檔案夾下的diemns檔案應該怎麼編寫呢?這個檔案夾下,意味著手機的最小寬度的dp值是360,我們把360dp等分成375等份,每一個設計稿中的像素,大概代表smallestWidth值為360dp的手機中的0.96dp,那麼接下來的事情就很簡單了,假如設計稿上出現了一個10px*10px的ImageView,那麼,我們就可以不假思索的在layout檔案中寫下對應的尺寸。

而這種diemns引用,在不同的values-sw<N>dp檔案夾下的數值是不同的,比如values-sw360dp和values-sw400dp,

當系統識別到手機的smallestWidth值時,就會自動去尋找和目標資料最近的資源檔的尺寸。
其次,從穩定性上,它也優於上述方案。原生的dp適配可能會碰到Pixel 2這種有些特別的手機需要單獨適配,但是在smallestWidth適配中,通過計算Pixel 2手機的的smallestWidth的值是411,我們只需要產生一個values-sw411dp(或者取整產生values-sw410dp也沒問題)就能解決問題。
smallestWidth的適配機制由系統保證,我們只需要針對這套規則產生對應的資源檔即可,不會出現什麼難以解決的問題,也根本不會影響我們的商務邏輯代碼,而且只要我們產生的資源檔分布合理,,即使對應的smallestWidth值沒有找到完全對應的資源檔,它也能向下相容,尋找最接近的資源檔。
當然,smallestWidth適配方案有一個小問題,那就是它是在Android 3.2 以後引入的,Google的本意是用它來適配平板的布局檔案(但是實際上顯然用於diemns適配的效果更好),不過目前所有的項目應該最低支援版本應該都是4.0了(糗事百科這麼老的項目最低都是4.0哦),所以,這問題其實也不重要了。
評論中還說到了一個缺陷我忘了提,那就是多個dimens檔案可能導致apk變大,這是事實,根據產生的dimens檔案的覆蓋範圍和尺寸範圍,apk可能會增大300kb-800kb左右,目前糗百的dimens檔案大小是406kb,我認為這是可以接受的。
今日頭條適配方案(更新)
文章連結,之前確實沒有接觸過,我簡單看了一遍,可以說,這也是相對比較完美的方案,我先簡單說一下這個方案的思路,它是通過修改density值,強行把所有不同尺寸解析度的手機的寬度dp值改成一個統一的值,這樣就解決了所有的適配問題。
比如,設計稿寬度是360px,那麼開發這邊就會把目標dp值設為360dp,在不同的裝置中,動態修改density值,從而保證(手機像素寬度)px/density這個值始終是360dp,這樣的話,就能保證UI在不同的裝置上表現一致了。
這個方案侵入性很低,而且也沒有涉及私人API,應該也是極不錯的方案,我暫時也想不到強行修改density是否會有其他影響,既然有今日頭條的大廠在用,穩定性應當是有保證的。
但是根據我的觀察,這套方案對老項目是不太友好的,因為修改了系統的density值之後,整個布局的實際尺寸都會發生改變,如果想要在老專案檔中使用,恐怕整個布局檔案中的尺寸都可能要重新按照設計稿修改一遍才行。因此,如果你是在維護或者改造老項目,使用這套方案就要三思了。
福利贈送
產生diemns檔案的過程以及資料計算方法上面已經講清楚了,大家完全可以自己去產生這些檔案,我在這裡附贈產生values-sw的項目代碼,大家直接拿去用,是Java工程。點擊這裡擷取項目地址
關於一些問題
Q: 該適配方案怎麼用?
A:點擊進入上文的github項目,下載到本地,然後運行該Java工程,會在本地根目錄下產生相應的檔案,如果需要產生更多尺寸,在DimenTypes 檔案中填寫你需要的尺寸即可。
Q: 是否有推薦的尺寸?
A 300,320,360,411,450,這幾個尺寸是比較必要的,然後在其中插入一些其他的尺寸即可,如果不放心,可以在300-450之間,以10為步長產生十幾個檔案。
Q:平板適配的問題?
A: 這個可以分成兩個問題,第一,團隊有沒有專門針對平板設計UI?第二,才是如何對平板適配。如果團隊內部沒有針對平板設計UI,那麼大家對於App在平板上啟動並執行要求大抵也就是不要太難看即可。針對這種情況的適配方法是被動適配,即不要產生480以上的適配檔案,這樣在平板上,系統就會使用480這個尺寸的dimens檔案,這樣效果比主動適配更好;而如果團隊主動設計了平板的UI,那麼我們就需要主動產生平板的適配檔案,大概在600-800之間,關鍵尺寸是640,768。然後按照UI設計的圖來寫即可。
Q:用了這套方案是否就不需要使用wrap_content等來布局了?
A:這是絕對錯誤的做法!如果UI設計上明顯更適合使用wrap_content,match_parent,layout_weight等,我們就要毫不猶豫的使用,而且在高這個維度上,我們要依照情況設計為可滑動的方式,或者match_parent,盡量不要寫死。總之,所有的適配方案都不是用來取代match_parent,wrap_content的,而是用來完善他們的。

Android 目前最穩定和高效的UI適配方案

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.