① android-屏幕適配全攻略(絕對詳細)(一)
關鍵字: 屏幕適配 px dp dpi sp large限定符 .9.png
前言: 這篇文章依然是我在 [慕課網 ][h]學習 凱子哥 的同名視頻 Android-屏幕適配全攻略 ,所記錄下來的筆記---凱子哥講得真的超詳細。
[h]: http://www.imooc.com/ "MOOC"
從上圖可以看出,主流的解析度是前六種:1280×720、1920×1080、800×480、854×480、960×540、1184×720,不過我們有解決方案。看完這篇文章,想必你就可以解決常見的屏幕適配問題。
接下來正式進入正題。
介紹幾個在Android屏幕適配上非常重要的名詞:
屏幕尺寸 是指屏幕對角線的長度。單位是英寸,1英寸=2.54厘米
屏幕解析度 是指在橫縱向上的像素點數,單位是px,1px=1像素點,一般是縱向像素橫向像素,如1280×720
屏幕像素密度 是指每英寸上的像素點數,單位是dpi,即「dot per inch」的縮寫,像素密度和屏幕尺寸和屏幕解析度有關
dip: Density Independent Pixels(密度無關像素)的縮寫。以 160dpi 為基準,1dp=1px
dp: 同 dip
dpi: 屏幕像素密度的單位,「dot per inch」的縮寫
px: 像素,物理上的絕對單位
sp: Scale-Independent Pixels的縮寫,可以根據文字大小首選項自動進行縮放。Google推薦我們使用12sp以上的大小,通常可以使用12sp,14sp,18sp,22sp,最好不要使用奇數和小數。
用於區分不同的像素密度。
在Google官方開發文檔中,說明了 ** mdpi:hdpi:xhdpi:xxhdpi:xxxhdpi=2:3:4:6:8 ** 的尺寸比例進行縮放。例如,一個圖標的大小為48×48dp,表示在mdpi上,實際大小為48×48px,在hdpi像素密度上,實際尺寸為mdpi上的1.5倍,即72×72px,以此類推。
我們可以通過以下幾種方式來支持各種屏幕尺寸:
wrap_content: 根據控制項的內容設置控制項的尺寸
math_parent: 根據父控制項的尺寸大小設置控制項的尺寸
weight: 權重,在線性布局中可以使用weight屬性設置控制項所佔的比例
例如,我們要實現下圖所顯示的效果:當屏幕尺寸改變時,new reader控制項兩邊的控制項大小不變,new reader控制項會占完剩餘的空間。
具體布局文件如下:
小插曲: 關於 android:layout_weight 屬性
一般情況,我們都是設置要進行比例分配的方向的寬度為0dp,然後再用權重進行分配。如下:
效果為:
效果為:
button1寬度=L+(L-2L)×1/3=2/3L
button2寬度=L+(L-2L)×2/3=1/3L
當然,還有其他的方式,都可以運用此公式進行計算。
在實際開發中,我們一般使用0dp的方式,而不使用其他方式。
簡單的布局一般都使用 線性布局 ,而略微復雜點的布局,我們使用 相對布局 ,大多數時候,我們都是使用這兩種布局的嵌套。
我們使用 相對布局 的原因是, 相對布局 能在各種尺寸的屏幕上保持控制項間的相對位置。
res/layout/main.xml 單面板:
res/layout-large/main.xml 雙面板:
如果這個程序運行在屏幕尺寸大於7inch的設備上,系統就會載入 res/layout-large/main.xml 而不是 res/layout/main.xml ,在小於7inch的設備上就會載入 res/layout/main.xml 。
需要注意的是,這種通過 large 限定符分辨屏幕尺寸的方法,適用於android3.2之前。在android3.2之後,為了更精確地分辨屏幕尺寸大小,Google推出了最小寬度限定符。
res/layout-sw600dp/main.xml ,雙面板布局: Small Width 最小寬度
這種方式是不區分屏幕方向的。這種最小寬度限定符適用於android3.2之後,所以如果要適配android全部的版本,就要使用 large 限定符和 sw600dp 文件同時存在於項目 res 目錄下。
這就要求我們維護兩個相同功能的文件。為了避免繁瑣操作,我們就要使用布局別名。
由於後兩個文具文件一樣,我們可以用以下兩個文件代替上面三個布局文件:
res/layout/main.xml 單面板布局
res/layout/main_twopanes.xml 雙面板布局
然後在 res 下建立
res/values/layout.xml 、
res/values-large/layout.xml 、
res/values-sw600dp/layout.xml 三個文件。
默認布局
res/values/layout.xml :
Android3.2之前的平板布局
res/values-large/layout.xml :
Android3.2之後的平板布局
res/values-sw600dp/layout.xml :
這樣就有了 main 為別名的布局。
在activity中 setContentView(R.layout.main);
這樣,程序在運行時,就會檢測手機的屏幕大小,如果是平板設備就會載入 res/layout/main_twopanes.xml ,如果是手機設備,就會載入 res/layout/main.xml 。我們就解決了只使用一個布局文件來適配android3.2前後的所有平板設備。
如果我們要求給橫屏、豎屏顯示的布局不一樣。就可以使用 屏幕方向限定符 來實現。
例如,要在平板上實現橫豎屏顯示不用的布局,可以用以下方式實現。
res/values-sw600dp-land/layouts.xml :橫屏
res/values-sw600dp-port/layouts.xml :豎屏
自動拉伸點陣圖,即android下特有的 .9.png 圖片格式。
當我們需要使圖片在拉伸後還能保持一定的顯示效果,比如,不能使圖片中的重要像素拉伸,不能使內容區域受到拉伸的影響,我們就可以使用 .9.png 圖來實現。
要使用 .9.png ,必須先得創建 .9.png 圖片,androidSDK給我們提供了的工具就包含 .9.png 文件的創建和修改工具。雙擊 SDK安裝目錄 oolsdraw9patch.bat ,就會打開下圖所示的窗口。
下面是一個例子:
Button屬性設置:
如果我們選擇的內容區域偏差太大,可能就不會顯示出text值 BUTTON 。
好了,這篇文章寫的有點多了,剩下的內容放在 下篇文章 記錄吧。
內容提要:
解決方案-支持各種屏幕密度
解決方案-實施自適應用戶界面流程
未完待續
② android屏幕適配有哪些方法
Android 資源文件夾有其中兩種方式支持屏幕適配:
一、方法:
1.XXX XXX-ldpi XXX-mdpi XXX-hdpi XXX-xhdpi XXX-xxhdpi 這種方式 (推薦使用)
2.XXX XXX-123x456 後面是具體值(不推薦使用這種方式!)
當我們做適配處理時通常會在以上一堆文件夾中定義 xxx.xml 例如 定義一個 : <dimen name="list_item_height">100dip</dimen>
二、適配舉例:
Android的匹配機制和手機系統有關:
規則一:Android4.0 以上的手機,先尋找和設備吻合的文件夾里的相應文件里的資源,如果沒有找到會繼續匹配它下面(比它解析度或密度小)的一些文件夾,最後去XXX 默認文件夾中匹配。
eg1: 小米2s (4.1 1280x720) 有文件夾 XXX XXX-320x240 XXX-800x480 XXX-1280x719 XXX-1280x720 XXX-1280x721 XXX-xhdpi
1.匹配XXX-xhdpi
2.匹配XXX-1280x720
3.匹配XXX-1280x719
4.匹配XXX-480x800
5.匹配XXX-320x240
6.匹配XXX
eg2:HTC ONE (4.2 1920×1080)
規則二:Android4.0 以下的手機,先尋找和設備吻合的文件夾里的相應文件里的資源,如果沒有找到會繼續匹配它下面(比它密度小)的一些文件夾。
eg:三星m250L(同三星9100 2.3.7 800x480) 有文件夾 XXX XXX-320x240 XXX-800x479 XXX-480x800 XXX-ldpi XXX-mdpi XXX-hdpi
1.匹配XXX-hdpi
2.匹配XXX-mdpi
3.匹配XXX-480x800
4.匹配XXX
5.匹配XXX-ldpi
6.程序退出
eg3:華為U8860(2.3.6 854x480)
所以在項目中<dimen name="list_item_height">50dip</dimen> 分別定義在
values : <dimen name="list_item_height">50dip</dimen> 和
values-320x240 : <dimen name="list_item_height">42dip</dimen> 中.
小米2s 會取 values-320x240 中42dip 的值。
③ android屏幕適配
android設備碎片化嚴重,因此在實際開發的時候需要做屏幕適配
適配主要是在以下幾個方面:
常見的布局適配主要是以下幾點:
a.避免寫死布局尺寸,使用wrap_content或者martch_parent
b.使用權重,比如linearlayout中的weight;
c.使用relative的相對位置擺放,比如layout_centerInParent="true"
d.ConstraintLayout 原理類似於relatvie,相對擺放,但是性能相對於relatvie會好一點
e.android官方的庫Percent-support-lib,該庫主要是用的是百分比適配
a. .9圖適配,這個是使用了.9圖可以在特別區域拉伸不失真的特性來適配
b. 使用多套點陣圖,匹配不同的解析度,比如在mipmap,mipmap-xhdpi,mipmap-xxhdpi,等文件夾下面放多套解析度不同的內容相同的圖片
是指同一個業務邏輯,在不同的設備上執行不同的跳轉方式,比如在手機上打開一個新的activity,但是在平板上,可以在橫屏狀態下,右側增加一個fragment,展示打開的頁面。
a.解析度限定符,使用drawable-dpi,drawable-hdpi等
b.尺寸限定符
c.最小寬度限定符
d.屏幕方向限定符
a.android9.0開始 有官方的api進行適配
b.華為,小米,魅族,vivo,oppo各大room廠商有對應的api進行適配
除了以上這些,還有dimens適配,但是都各有缺點,有的需要多套圖,有的需要多套資源文件,dimens適配的dimens文件過多,需要針對不同的屏幕解析度來生成對應的文件,比較繁瑣
以上,實際開發中,做的最多的適配為布局適配
開發中屏幕適配的核心是在於屏幕縮放,不論是哪種屏幕適配,都是以這個縮放為基礎
已知:設計圖手機像素(W,H),設計圖上控制項的像素值(ViewW,ViewH),目標設備解析度(TargetW,TargetH)
求:目標設備上view的寬高(TargetViewW,TargetViewH)
公式:寬:ViewW / W * TargetW=TargetViewW
高:ViewH / H * TargetH =TargetViewH
原理:根據當前設備的解析度,計算出設計圖上的控制項在該設備上的縮放比,然後根據縮放比,來動態的設置view, 最終換算出來的單位為px
該適配方式是通過自定義外部的ViewGroup,比如LinearLayout,RelativeLayout,在onMeasure方法中,遍歷子view,設置寬高以及padding,margin
以下是封裝了一個工具類,用來獲取屏幕寬高以及計算縮放比:
未完待續
④ Android 屏幕適配
Android的屏幕大同小異,解析度也是各種各樣,手機App上的差異性還沒那麼明顯,基本用Dp & weight就可以比較好的適配各種手機。但是在Pad上的表現就不盡如意,而且發現像華為Pad Pro這種高端設備,是可以通過系統設置去設置修改系統的density值,導致整個如果只用一套DpUI布局去實現,會出現很奇怪的UI效果,基本不能適配。這時候就需要對UI進行適配。通過資料查詢,需要了解如下的幾個概念
1.px,pixel 就是像素,最基本的真實顯示單位
2.dp,dip, Density-independent pixel,設備的獨立像素,1dp表示在屏幕像素點密度為160ppi時1px長度
3.ppi, pixel per inch ,每英寸對角像素點,這個是物理上的
4.dpi, dot per inch ,每英寸多少個點,這個是軟體上的,這里的點跟像素點不同
5.sp: scale-independent pixel, 字體大小單位
簡單換算就是
ppi =根號( 橫屏像素點平方+縱屏像素點平方)➗對角線的長度,這個長度是一英寸
1dp = (dpi/160) px
然後有些不同尺寸手機的ppi可能是420, 430, 440, 450, 460.,由於物理ppi上是固定的,改變不了,為了適配,通過人為設置一個dpi,來規范這些差不多ppi值,使得這些相差差不多的屏幕都是通用一個dpi,也就是使用同一套設計方案。
一開始通過dp值來實現適配,是可以解決大部分適配問題,但是在遇到pad這種設備,由於是橫屏,而且系統設置還可以修改density值,使得用一套固定屏幕(比如1280 * 800)的方向變得不是那麼合適。
這時候想到可以通過Android中 dimens中定義dimen值,Android中可以通過sw去搜索對應的dimen值表來獲取對應的配置,smallestWidth適配,sw限定符適配,只要我們把對應的表通過換算,得到一個新值,就可以得到在不同的density值中得到對應的dp值表,解決華為上一個設備對應不同density值的問題。
那麼問題來了,如果去得到sw不同的dimens呢,網上的方法很多,有些自己寫腳本,有些自己寫程序生成,為了就是列舉所有的值,一般1-1000dp,然後基於一個基準,比如360dp寬度,去換算出不同屏幕寬度的dimens值,這里我推薦Android Studio的插件ScreenMatch,先安裝插件
然後在values中創建dimens文件夾,並創建dimens.xml,其中寫上自己定義的dp值,如下
然後在該文件右鍵,選擇screenmatch
插件就會生成一堆其他屏幕的dimens文件,並且自動生成1-800的其他dp值,基本滿足開發中的定義,如果沒有的話,就自行在這里定義,然後重新生成。
關於ScreenMatch的生成還有一個基準,就是基於那個dpi來生成,通過插件生成,在根目錄會多出了兩個文件,一個example, 一個config文件
這里我們看看properties文件,內容如下
其中base_dp=850就是基於850,然後可以通過match_dp去調整要適配的dpi值。
通過這方方式,會在dimens文件自動生成dimen文件
在網上看到,還可以通過修改density去修改,這種方式有空我在試試
⑤ Android切圖適配知識點匯總
對於在工作中沒有接觸過安卓版本app,或是面試的時候會被問到安卓解析度等問題,可以通過本文對安卓切圖有所了解。我在以往的工作中也沒有接觸過安卓設計等一系列問題,但是看完一些文章後,大致對安卓解析度等知識點有所了解。此文是對自己所了解到的知識做一個總結,也希望能幫助到不了解安卓一系列問題的同行們,好啦,馬上進入正題!
基本概念
1、手機屏幕尺寸計算方式:對角線尺寸/2.54(1英寸=2.54厘米)
2、解析度:屏幕上顯示的像素個數,單位尺寸內像素點越多,顯示的圖像就越清楚。
上圖中紅框框出來的是現在市場上主流的解析度,只要記這三個就可以。其他的已被淘汰。
3、屏幕密度:屏幕每英寸有多少個像素。
4、單位:dp是開發中用於描述尺寸和間距。
sp是用於描述字型大小和行距。
用哪種解析度來設計?
原則上需要為不同的解析度去單獨設計效果圖,但由於實際情況,只需要採用一種解析度去設計,目前多數採用720*1280的解析度。
需要提供幾套切圖?
只需要一套切圖即可
720*1280尺寸的切圖可以適配其他機型,有些特殊的切圖需要單獨適配的,比如icon等。
適配480 800的機型,只需要把切圖/1.5即可。
適配1080 1920的機型,只需要把切圖*1.5即可。適配此解析度的時候,需要在720 1280下畫圖的時候,盡量採用矢量圖形來畫圖。
例如,圖標是48 48的時候,適配1080 1920點時候,48px*1.5=72px.把矢量圖形調整為72px即可。開發會把切圖放到xxhdpi的文件目錄下,就會自動適配1080 1920
同樣,適配480 800的時候,48px/1.5=32px.開發把切圖放到hdpi文件目錄中,會自動適配。
720 1280的切圖,開發放到xhdpi的目錄下。
註:設計圖片的時候盡量採用偶數。
需要提供幾套標注?
在720*1280解析度下進行設計,此解析度下1dp=2px.
可以直接使用dp標注尺寸,sp標注文字大小
註:使用dp標注尺寸。使用sp標注文字大小
該使用什麼字體及字型大小?
中文字體:思源
英文字體:Android 4.x及以上採用Roboto,Android 2.x和3.x採用Droid Sans.
字型大小:12sp、14sp、18sp、22sp(也可根據實際情況調整)
目前掌握以上知識點,可能多少也有些小問題,歡迎有經驗的大神指正、指導。謝謝啦~
⑥ android屏幕適配做哪幾個尺寸
android屏幕適配尺寸有全屏模式、4:9、8:12多種。
android屏幕適配尺寸有多種,具體的要結合自己的興趣愛好和手機的自身的實際情況,具體設置標准如下:
1、不要使用絕對布局,這會限制你的手機屏幕的更換。
2、盡量使用match_parent ,從而保證屏幕的最大化利用。
3、盡量使用權重(android:layout_weight),保持手機屏幕合理布局。
4、盡量使用android的shape 自定義,形成純色背景。
5、可以在res目錄上新建layout-HxW.xml的文件夾進行在特定解析度下適配。
拓展資料:
由於筆記本電腦採用的液晶屏的大小和解析度是根據它的市場定位決定的,所以為了適應不同人群的消費能力和使用習慣,筆記本電腦的液晶顯示器的尺寸和解析度種類遠遠要比台式液晶顯示器多。
⑦ 怎麼樣讓Android實現全屏幕適配
一、關於布局適配
1、不要使用絕對布局
2、盡量使用match_parent 而不是fill_parent 。
3、能夠使用權重的地方盡量使用權重(android:layout_weight)
4、如果是純色背景,盡量使用android的shape 自定義。
5、如果需要在特定解析度下適配,可以在res目錄上新建layout-HxW.xml的文件夾。比如要適配1080*1800的屏幕(魅族MX3採用此解析度)則新建layout-1800x1080.xml的文件夾,然後在下面定義布局。Android系統會優先查找解析度相同的布局,如果不存在則換使用默認的layout下的布局。
二、關於圖片製作
1、關於設計:
設計圖先定下一個要設計的尺寸,而且盡量採用在目前最流行的屏幕尺寸(比如目前占屏幕比重比較多的是480系列,也即是480*800或者400*854,下面的圖標製作也在次基礎上進行比例的換算)上設計。
先了解一下屏幕的級別:
屏幕級別:
注意屏幕級別是按照密度分級,和像素沒有關系。如果非要讓密度和像素扯上關系,則需要一個參照系,android使用mdpi級別作為標准參照屏幕,也就是說在320*480解析度的手機上一個密度可以容納一個像素。然後其他密度級別則在此基礎上進行對比。如果理想情況下,480*800的屏幕一個密度可以容納1.5個像素。
物理大小:
單位是英寸而不是像素,也就說一個英寸在任何解析度下顯示的大小都是一樣的,但是像素在密度不同的手機裡面顯示的實際的大小是不一樣的(這就是為什麼android手機需要適配的原因)。
然後就是重點。
假設1像素在160密度下顯示1英寸,則1像素在240密度基礎上顯示大約0.67英寸,在320密度下顯示0.5英寸。於是就出現一種情況,在電腦上的一個像素,在不同的手機上看實際的大小不一樣。那麼怎麼讓「設計效果」在不同的手機上看起來顯示的區域一樣呢?
還是假設一個像素在160密度下的顯示在一個密度內,也假設就是一英寸。那麼需要幾個像素才能在240密度級別下顯示在一英寸范圍內呢?答案是1.5個像素(根據上圖的比率換算)。
了解了這個關系,接下來就是圖標的製作。
2、關於切圖。
關於切圖有幾個建議:
第一,長寬最好是3的倍數(根據android的推薦logo圖標的大小是48(mdpi),72(hdpi),96(xhdpi)得出的最小公約數)。
第二,長寬最好是偶數。因為奇數在進行等比壓縮的時候可能有問題。
第三,根據上面兩條,如果長寬是6的倍數最理想。
第四,如果可以拉伸而不改變設計意圖的情況下,比如純色背景,則使用android的9path工具製作成.9的圖片。
3、關於圖標的適配。
然後接下來的一切就和設計稿沒什麼關系。在切好圖的基礎上,根據屏幕密度、像素和實際大小的比例關系。假如設計司在480*800的解析度下做好了設計圖,並且切好圖,如果你需要適配720*1280屏幕,該怎麼做?根據比例,他們的關系是2:3,於是你需要按照1.5倍比例製作圖標,比如你在480*800的設計稿上切下來一個20*20像素的圖,那麼你就需要製作一個等比放大成30*30像素的圖標,這樣同一個圖標在480*800的屏幕和720*1280的屏幕上顯示的實際大小才一樣。同理,如果你需要適配xxhdpi則需要在20*20的基礎上製作一個等比放大成40*40像素的圖標。
4、關於圖標的目錄,480*800切下來的圖我們放在drawable-hdpi目錄下,按照2:3放大的圖標放在drawable-xhdpi目錄下,按照2倍放大的圖標放在drawable-xxhdpi目錄下。
android會根據手機的密度優先查找對應的目錄的資源,
比如408*800解析度下的手機如果密度是160,則自動載入drawable-hdpi這個目錄下的圖標,
如果720*1280密度是240的手機自動載入drawable-xhdpi這個目錄下的圖標。如果沒有這個文件夾,則查找和240最接近的對應密度文件夾。
三、其它
接下來要說的估計會讓你失望,根據上面的步驟也不能完全解決適配的問題,只能是大概適配,而就算根據上面的步驟大概適配了,實際在手機上的效果也有出入。
比如魅族MX3的解析度是1080*1800,標准情況下密度是480,但是他的密度大約是524,和480接近,也就是會查找drawable-xxhdpi這個資源下的文件。也就是說你在480*800解析度下切圖然後按兩倍放大的圖標在這台手機上顯示的效果還是比實際的小。
而另一個要說的問題是540*960或者640*960,他們的密度很可能是或者接近240也可能是320。於是在480*800的設計稿上切下來的圖並且進行的適配製作,在這些手機上顯示的實際大小也可能或大或小。
⑧ Android 屏幕解析度適配
Android屏幕解析度千奇百怪,怎麼讓app在不同的解析度的設備上「看起來一樣」呢?
你也許還有以下疑惑:
這篇文章將會針對以上問題一一解答。
Pixels 我們看到屏幕上的圖像由一個個像素組成,像素里包含色彩信息。
如常說的手機解析度:1080 x 1920 指的是手機寬度可展示1080像素,高度可展示1920像素。
Pixels Per Inch 每英寸長度所具有的像素個數,單位面積內像素越多,圖像顯示越清晰。
ppi一般用在顯示器、手機、平板等描述屏幕精細度。
Dots Per Inch 每英寸長度所具有的點數。
dpi一般用來描述列印(書本、雜志、電報)的精細度
density-independent pixels (device-independent pixels 我查了一下,官網更多時候使用前者,有的時候也顯示後者),dip是縮寫,也可以更簡單些稱作dp。該單位的目的是屏蔽不同設備密度差異,後面細說。
Scalable pixels 用於設置字體,在用戶更改字體大小時候會適配。
澄清了基本概念,我們現在從一個例子開始說明以上單位之間的區別與聯系。
布局文件里有個View,長寬都是200px,分別在解析度為480(寬)x800(高)簡稱A設備、1080(寬)x1920(高)簡稱B設備,效果如下:
左邊是A設備,右邊是B設備。問題出來了,同樣長寬都是200px,為啥A設備顯示很大,B設備顯示很小呢?你可能會說B設備的橫向解析度1080比A設備的480大,所以在B設備上看起來比較小。來看看A、B設備橫向到底是多少英寸,怎麼來計算呢?這時候就需要用到ppi了,既然知道橫向的像素點個數,也知道每英寸能容納的像素點,當然可以得知橫向的尺寸了。
其中一種方式獲取DisplayMetrics對象:
A設備寬度尺寸:480(px)/240(ppi)=2inch
B設備寬度尺寸:1080(px)/420(ppi)=2.5inch
可以看出,A、B設備尺寸差別不大。A設備ppi=240 B設備ppi=420,明顯地看出B設備單位長度上比A設備能夠容納更多的像素,因此同樣的200px,B設備只需要較小的尺寸就能夠顯示,因此在B設備上的view看起來比A設備小很多。
知道了問題的原因,然而顯示的效果卻不能接受。
我們總不能自己判斷每個設備的ppi,然後計算實際需要多少像素,再動態設置view的大小吧,那layout里的靜態布局大小就無法動態更改適應了。想當然的能有一個統一的地方替我們轉換,沒錯!Android系統已經幫我們實現了轉換。接下來就是dpi、dp出場了。
Android系統使用dpi來描述屏幕的密度,使用dp來描述密度與像素的關系。
A設備dpi=240
B設備dpi=420
Android系統最終識別的單位是px,怎麼將dpi和px關聯起來呢?,答案是dp。
Android規定當dpi=160時,1dp=1px,當dpi=240時,1dp=1.5px,依此類推,並且給各個范圍的dpi取了簡易的名字加以直觀的識別,如120<dpi<=160,稱作為mdpi,120<dpi<=240 稱作hdpi,最終形成如下規則:
現在知道了dp能夠在不同dpi設備上對應不同px,相當於中間轉換層,我們只需要將view長寬單位設置為合適的dp,就無需關注設備之間密度差異,系統會幫我們完成dp-px轉換。將我們之前的例子稍微更改,再看看效果驗證一下:
通過上面對dp的了解,我們知道在設定view大小、間距時使用dp能最大限度地屏蔽設備密度之間的差異。可能你就會問了,那bitmap展示的時候如何適配不同密度的設備呢?
自定義view從磁碟上載入一張圖片,並將之顯示在view上,view的大小決定於bitmap大小。依舊以上述A、B設備為例,展示結果如下:
左邊是A設備,右邊是B設備。
明顯地看出,在A設備顯示比B設備大很多,實際上和我們之前用px來描述view的大小原理是一樣的,bitmap的寬、高都是px在描述,而bitmap決定了view的寬、高,最終導致A設備和B設備上的view大小(寬、高像素)是一樣的,而它們屏幕密度又不相同,因此產生了差異。
那不會每次都需要我們自己根據屏幕密度來轉換bitmap大小吧?幸運的是,Android已經為我們考慮到了。
生成不同密度的目錄有什麼作用?
A設備dpi=240,根據dpi范圍,屬於hdpi
B設備dpi=420,根據dpi范圍,屬於xxhdpi
圖片原始尺寸:photo1.jpg(寬高 172px-172px)
當我們想要在不同密度設備上顯示同一張圖片並且想要「看起來一樣大時」。假設設計的時候以hdpi為准,放置photo1.jpg為172*172,那麼根據計算規則在xxhdpi上需要設置photo1.jpg為:
現在hdpi和xxhdpi目錄下分別存放了同名圖片:photo1.jpg,只是大小不同。當程序運行的時候:
來看看效果:
左邊A設備,右邊B設備
針對不同的密度設計不同的圖片大小,最大限度保證了同一圖片在不同密度設備上表現「看起來差不多大」。
來看看A、B設備上圖片占內存大小:
說明在B設備上顯示photo1.jpg需要更多的內存。
上邊只是列舉了hdpi、xxhdipi,同理對於mdpi、xhdpi、xxxhdpi根據規則放入相應大小的圖片,程序會根據不同的設備密度從對應的mipmap文件夾下載入資源。如此一來,我們無需關注bitmap在不同密度設備上顯示問題了。
在mipmap各個文件夾下都放置同一套資源的不同尺寸文件似乎有點太佔apk大小,能否只放某個密度下圖片,其餘的靠系統自己適配呢?
現在只保留hdpi下的photo1.jpg圖片,看看在A、B設備上運行情況如何:
看起來和上張圖差不多,說明系統會幫我們適配B設備上的圖片。
再來看看A、B設備上圖片占內存大小:
先看A設備:
對比photo1.jpg 分別放在hdpi、xxhdpi和只放在hdpi下可以看出:B設備上圖片所佔內存變小了。為什麼呢?接下來從源碼里尋找答案。
A、B設備同樣載入hdpi/photo1.jpg,返回的bitmap大小不相同,我們從這方法開始一探究竟。
上面涉及到的關鍵點是density,分別是TypedValue的density和Options的density。
先來看看TypedValue density:
再來看看Options density
現在分析B設備載入hdpi/photo1.jpg如何做的:
和我們之前調試的結果一致。
B設備是怎麼決定使用hdpi下的圖片資源呢?
根據實驗(嘗試找了源碼,沒怎麼看懂,因此只是做了實驗,可能在不同密度設備上找尋規則不一樣):B設備先找屬於自己密度范圍文件夾下的圖片,B設備屬於xxhdpi,先查看xxhdpi有沒有photo1.jpg,如果沒有則往更高的密度找,比它高的密度是xxxhdpi,還是沒有,則往低密度找,找xhdpi,沒有再找hdpi,找到了則返回構造好的TypedValue,剩下的就是我們前面分析的。
既然我們只想放某個密度下的一份切圖,該放哪個密度下呢?從系統尋找規則看,更推薦放置在更高密度下的,因為如果放在低密度下,那麼當運行在高密度設備上時,圖片會進行放大,可能導致不清晰。我一般習慣放在xxhdpi下。
Android Studio默認創建了不同密度的mipmap文件夾,默認放置了ic_launcher.png。我們普通的切圖該放drawable還是mipmap下呢?對於這個問題網上也是眾說紛紜,實際上對於我們來說,關注的重點是圖片放在drawable或者mipmap,載入出來bitmap是否有差異,如果沒有差異放在哪就看習慣了。通過實踐,普通的切圖放drawable和mipmap下載入出來的bitmap是沒有差異的,只不過用drawable的話需要自己創建不同密度的文件夾。我習慣於放在drawable下(啟動圖標logo還是放在mipmap下)。
前邊 [注1] 留了個問題,我們使用dp來表示view的大小了,為啥兩個看起來還是有些差距?下面我們更加直觀地看一個例子。
A設備dpi=240 密度1.5 解析度(寬高px):480 * 800
B設備dpi=420 密度2.625 解析度(寬高px):1080 * 1794
換算成dp
A設備解析度:320dp * 533dp
B設備解析度:411dp * 683dp
依舊是上邊的例子:
將view寬高分別設置為320dp,看看效果:
左邊A設備,右邊B設備
可以看出同樣的320dp大小,A設備鋪滿了屏幕,而B設備沒有。這效果顯然是不能接受的,Android考慮到不同設備寬高不同,推出了"寬高限定符"。以A、B設備為例:
在res文件夾下創建文件夾:
假設設計師出圖是按照800x480,那麼我們創建dimen文件的時候
該文件放在values-800x480文件夾下。
根據解析度比例算出1794x1080的dimen值
這樣子,A、B設備載入資源的時候使用對應解析度限定符下的px,如果找不到再找默認值,可以在一定程度上解決屏幕寬高碎片化適配問題。
但是這樣子的限定比較嚴格,需要測試各種解析度,後來Android又推出了"smallest-width"簡稱最小寬度限制。
A設備寬320dp
B設備寬411dp
假設設計師切圖標准屏幕寬是320dp(A設備),那麼可以定義如下dimen.xml文件
該文件放在values-sw320dp文件夾下
根據規則,計算B設備dimen.xml
現在我們繼續來看之前的view
通過對dimen引用,A設備尋找和自己寬度一樣的dimen文件,找到values-sw320dp,dp320=320dp。B設備尋找和自己寬度一樣的dimen文件,找到values-sw411dp,dp320=410dp。這樣子同樣的dp320,得出不同的值,就適配了屏幕寬度不同的問題。
看看效果:
這次B設備也鋪滿了屏寬。
綜上,為了適配不同屏幕大小,推薦使用dp+smallest-width。
獲取設備dpi最終都是從這方法獲取的,實際上就是讀取系統的配置文件。因此我們也可以通過adb shell 獲取:
可以看出dpi是系統配置好的,當然有些手機是可以設置解析度的,設置之後我們查看解析度:
解析度變低了,dpi也變小了。
⑨ 屏幕適配那些事(02)Android邏輯像素刨根問底
屏幕適配是一個老生常談的問題了,我用這三篇博客和大家討論點屏幕適配相關的干貨。
iOS的屏幕規格可以列舉處理,iPhone4及更新的設備,只有4種規格,他們的邏輯解析度像也是固定的。Android這邊就比較復雜了,理論上可以出現無數種邏輯解析度。Android的邏輯解析度可以通過三個步驟推導得到:
以Nexus 5為例:
你可能會問,按照上面的推導,屏幕像素密度越低(像素解析度相同,尺寸越大),邏輯解析度應該越高。但是上一節討論中,為什麼說「三星S7和三星S7 edge,屏幕尺寸分別為5.1和5.5英寸,但是他們顯示的內容是一樣多的(邏輯解析度一致)」?
是的,顯然S7和S7 edge的屏幕像素密度是不同的(尺寸不同但是像素解析度一致),但是為什麼邏輯像素密度會一樣呢?下面進行解釋:
Android SDK 中:
我們可以總結出一個 結論:Android設備,雖然屏幕解析度不同,但是通常相同大小屏幕的設備具有相同的邏輯解析度。
有什麼指導意義呢?Android設備雖然有數不清的屏幕規格,但是邏輯解析度的規格就沒有那麼多啦,而且可以方便的找到幾個參考值:360×640(大部分720P及以上手機屏幕)、411×731(部分2K屏幕)等,基準設計稿就可以參考這些值啦。
下一篇文章給出一點我對屏幕適配的建議。