㈠ 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也變小了。
㈡ Android屏幕配適、版本配適與多語言支持
目前主流的屏幕密度:240dpi (480 * 800px) , 320dpi (720*1280px) , 480dpi(1080*1920px)現在新出的手機幾乎全是全高清屏(1080*1920px)
Android圖片資源目錄
mdpi [1倍]160dpi
hdpi [1.5倍] 240dpi
xhdpi [2倍] 320dpi
xxhdpi [3倍] 480dpi
xxxhdpi [4倍] 640dpi
因此對其他圖片資源的建議是:
a.一般採用720 * 1280的屏幕尺寸設計,這樣切圖可以直接適配720 * 1280的機型。
b.720 * 1280下切的圖基本可以適配大部分機型。
d.適配480 * 800的機型,只需要把切圖 * 0.75。
e.適配1080 * 1920 的機型,只需要把切圖 * 1.50即可。
a.以720 * 1280作為設計標准,畫布大小定位720 * 1280 (以後1080*1920px做標准亦可,類推)
b.只使用偶數單位的尺寸
c.盡量只使用 24pt, 28pt , 32pt, 44pt大小的字體
d.設計完成之後,所有尺寸的px值除以2作為dp數據交給開發人員
e.三份切圖,分別是:xhdpi,hdpi,mdpi的資源,如果要切一份就使用xhdpi
柵格系統的最小單位是8dp,一切距離、尺寸都應該是8dp的整數倍,所有可操作元素最小點擊區域尺寸為48dp X 48dp。以下是一些常見的尺寸與距離:
有時候在自定義view,draw的時候單位往往是px,要做一個dpi的轉換,需要通過該類獲取屏幕的信息,如:屏幕密度,寬高等。
a.盡量使用線性布局(LinearLayout)和相對布局(RelateLayout),盡量不使用絕對布局(AbsoluteLayout)和幀布局(FrameLayout)。
b.盡量使用wrap_content、mach_parent讓view自適應或最大化,盡量不要寫寬高的值。
c.使用線下布局的百分比weight權重時,要把能伸縮方向的寬度寫成「0dp「,如果寫成wrap_coent會使布局效果不佳等問題。
d.盡量使用android的Shape自定義view背景,這樣會隨之自適應。
e.ImageView的ScaleType有幾種方式:matrix(默認)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY;盡量使用fitCenter按比例擴大至view寬度,能取得較好適配和顯示效果。(更多請參考: Android中的ImageView配適 )
f.獲取屏幕解析度信息,進行動態適配。(參考第三大點)
a.把屏幕設置成單一的橫屏或豎屏:
b.根據橫豎屏載入不同布局(android: screenOrientation="sensor")
通過this.getResources().getConfiguration().orientation來判斷當前是橫屏還是豎屏,然後在onCreate方法中載入不同的布局
採用第二種方式要注意的有兩點
布局問題:
需要在res目錄先建立layout-land和layout-port目錄相應的xml文件名字相同,然後在兩個文件夾下創建相同名字的兩套xml,系統就會根據不同的屏幕來進行自動尋找。
切換時activity的生命周期:
activity生命周期在切換橫豎屏會有一些有趣的變化
a.不設置activity的android:configChanges時,切換橫屏,activity的生命周期會重新調用一次,但是切換豎屏時,生命周期會重新調用兩次。
b.當設置activity的android:configChanges=「orientation」時,切換橫豎屏都會重新調用各生命周期一次。
c.當設置activity的android:configChanges=「orientation|keyboardHidden」(大於api13時,需要設為「orientation|screenSize」)時,切換橫豎屏不會重新調用各生命周期,只會調用onConfigurationChanged方法。
一般設為b或者c
平板應用的特性:
對於大屏幕的平板8英寸以上(參考ipad mini,現在很多高端手機都是5-6英寸了,8英寸以上視為平板吧),基與平板應用的特性,平板應用開發一般採取如下兩種策略
1)兼容模式
採用單activity(或者盡量少activity)+多fragment的結構開發應用,在layout資源文件中創建三套布局:手機布局、平板橫屏布局、平板豎屏布局。
優點:
只需要維護一個app
缺點:
設計及實現的難度變大,更復雜,有時候需要採取折衷方案
手機apk上由於含有平板的大解析度圖片資源(設計上可以減少內置資源)
2)開發另一套只適配平板的app
優點:
與手機app分離獨立。不會因為要兼容而採用一些折衷方案,影響其性能、內存
設計和實現更加自由
缺點:
需要維護兩套app
目前谷歌推薦第一種方案,但是國內很多應用是採取第二種方案。
可以通過判斷sdk的版本(Build.VERSION.SDK_INT),來為能夠使用的版本進行個性化設置
例如:沉浸式狀態欄配適
在Android系統4.4以前,狀態欄的背景色和字體顏色都是不能改變的。但是4.4以後Google增加了改變狀態欄背景透明的方法。可以通過判斷sdk的版本,來為能夠使用的版本進行個性化設置:
沉浸式狀態欄是Android在5.0中引入的,在5.0之前是沒有的,並且在Android6.0中沉浸式狀態欄的使用方法和5.0不一樣,因此需要做到版本兼容,針對於不同的Android進行適配,同樣也是通過判斷Build.VERSION.SDK_INT來區分版本,進行個性化配適
沉浸式狀態欄的實現方式有好幾種,更多請參考 沉浸式狀態欄的實現
原則:內置圖片資源不應該出現文字(如果出現文字需要具備)、所有的文字需要放在res資源目錄特定語言目錄下。
㈢ android app界面設計規范(dpi,dp,px等)
PPI(Pixels per inch):每英寸所擁有的像素數,即像素密度。
DPI(dots per inch):即每英寸上,所能印刷的網點數,一般稱為像素密度。ppi計算公式:ppi = 屏幕對角線像素數/屏幕對角線英寸數,通過勾股定理計算屏幕對角線像素數。
Screen Size(屏幕尺寸):手機屏幕尺寸大小,如3英寸、4英寸、4.3英寸、5.7英寸,指的是對角線的長度。
DIP(device independent pixel):即dip/dp,設備獨立像素。 1px = 1dp density(由dpi決定)
Resolution(解析度):指手機屏幕垂直和水平方向上的像素個數。eg解析度480 800,指該設備垂直方向有800個像素點,水平方向有480個像素點。
px(Pixel像素):相同像素的ui,在不同解析度的設備上效果不同。在小解析度設備上會放大導致失真,大解析度上被縮小。
Android Design里把主流設備的 dpi 歸成了四個檔次: 120 dpi、160 dpi、240 dpi、320 dpi ,具體見如下表格。
實際開發當中,我們經常需要對這幾個尺寸進行相互轉換(比如先在某個解析度下完成設計,然後縮放到其他尺寸微調後輸出),一般按照 dpi 之間的比例即 2:1.5:1:0.75 來給界面中的元素來進行尺寸定義。
也就是說如果以 160 dpi 作為基準的話,只要尺寸的 DP 是 4 的公倍數,XHDPI 下乘以 2,HDPI 下乘以 1.5,LDPI 下乘以 0.75 即可滿足所有尺寸下都是整數 pixel 。但假設以 240 dpi 作為標准,那需要 DP 是 3 的公倍數,XHDPI 下乘以 1.333,MDPI 下乘以 0.666 ,LDPI 下除以 2。而以 LDPI 和 XHDPI 為基準就更復雜了。同時第一款Android設備(HTC的T-Mobile G1)是屬於160dpi的。鑒於以上各種原因, 標准dpi=160
谷歌官方對dp的解釋如下:
A virtual pixel unit that you should use when defining UI layout, to express layout dimensions or position in a density-independent way.
The density-independent pixel is equivalent to one physical pixel on a 160 dpi screen, which is the baseline density assumed by the system for a "medium" density screen. At runtime, the system transparently handles any scaling of the dp units, as necessary, based on the actual density of the screen in use. The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160). For example, on a 240 dpi screen, 1 dp equals 1.5 physical pixels. You should always use dp units when defining your application's UI, to ensure proper display of your UI on screens with different densities.
簡單來說,以160dpi的設備為准,該設備上1dp = 1px;如果屏幕密度大,1dip代表的px就多,比如在320dpi的屏幕上,1dip=2px(即1dp代表2個像素)。在app開發時,最好用dp來做界面的布局,以保證適配不同屏幕密度的手機。
dp和px的換算公式:
我的理解,該公式表示px的數值等於dp的數值*(設備dpi/160)
注意,px、dp是單位,但density沒單位。
applyDimension的源碼如下,可參考:
android的尺寸眾多,建議使用解析度為 720x1280 的尺寸設計。這個尺寸 720x1280中顯示完美,在 1080x1920 中看起來也比較清晰;切圖後的圖片文件大小也適中,應用的內存消耗也不會過高。
app啟動圖標為48*48dp,對應各dpi設備,圖像資源像素如下:
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|48 48px|72 72px|94 96px|144px 144px|
操作欄圖標為32*32dp,對應各dpi設備,圖像資源像素如下:其中圖形區域尺寸是24*24dp,可參考平時ui切圖會有部分留白。
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|32 32px|48 48px|64 64px|96px 96px|
通知欄圖標為24*24dp,對應各dpi設備,圖標像素如下:
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|24 24px|36 36px|48 48px|72px 72px|
某些場景需要用到小圖標,大小應當是16*16dp,其中圖形區域尺寸12*12dp。
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|16 16px|24 24px|32 32px|48px 48px|
㈣ 探究安卓px/dp/dip/dpi/ppi/sp/density含義
dp=(160/ 像素密度值)px
so, xhdpi時,dp=1/2px;xxhdpi時,dp=1/3px;
ldpi QVGA (240×320)
mdpi HVGA (320×480)
hdpi WVGA (480×800), FWVGA (480×854)
xhdpi 720P(1280 720)
xxhdpi 1080p(1920 1080 )
xxxhdpi 4K(3840×2160)
px : pixels(像素)
ppi : pixels per inch(像素密度,所表示的是每英寸所擁有的像素數量)
dpi : dots per inch(每英寸的點數)
dp、dip : device independent pixels(設備獨立像素)
sp : scaled pixels(放大像素)
density:安卓系統中的density表示的是密度系數。計算方法是density = dpi / 160。即將160dpi作為標準的密度值(每英寸點數),我們設置的dp值即是在160的標准密度值下的像素數;所以px = density * dp。
PPI和DPI的含義區別?
PPI:pixels per inch(像素密度,所表示的是每英寸所擁有的像素數量)
為什麼解析度一樣,屏幕尺寸一樣, 同樣的dp值顯示出來的實際像素值不一樣?
答:PPI是固定計算的,和解析度,屏幕尺寸相關。DPI是ROM廠商設定的,不是確定公式計算的。同樣的解析度和屏幕尺寸,只能得到PPI一致。但是這不是實際顯示的結果,設置dp值是按照DPI來計算的,這個時候需要看設備實際的DPI值,DPI不同結果不同。廠商可能為了顯示效果而設置了不同的density(DPI).
㈤ Android 關於"尺寸"的那些事(dp,dip,sp,pt,px...)
屏幕大小:屏幕大小是手機對角線的物理尺寸,以英寸inch為單位。比如我的Mix 2手機屏幕大小為5.99 inches,意味著我的屏幕對角線長度為5.99inches = 5.99 * 2.54 = 15.2146cm
解析度:屏幕的像素點數,一般表示為a*b。例如某手機解析度為21601080,意味著手機屏幕的豎直方向(長)有2160個像素點,水平方向(寬)有1080個像素點。
px :Pixels ,像素;對應屏幕上的實際像素,是畫面中最小的點(單位色塊),像素大小沒有固定長度值,不同設備上1個單位像素色塊大小不同。
這么說可能有點陌生,用屏幕解析度來說,今年流行起來的「全面屏」解析度是 2160*1080,但是你也可以發現,雖然很多全面屏手機解析度一樣,但是明顯看得出來屏幕大小不一樣,這也解釋了「不同設備像素色塊大小是不同的」。
pt :1pt=1/72 inch,用於印刷業,非常簡單易用;
dpi :Dots Per Inch,每英寸點數;詳見ppi
ppi :Pixels Per Inch,每英寸像素數;數值越大顯示越細膩。計算式:ppi = 屏幕對角線像素數 / 屏幕對角線長度。
還是舉全面屏的例子,解析度2160*1080,屏幕大小是5.9inches,勾股定理可以得到對角線像素數大約是2415,那麼ppi = 2415 / 5.99 = 403.
事實上dpi 和 ppi 一定程度上可以劃等號,都表示像素密度,計算方式完全一致,只不過使用場景不一樣。dpi中的dots點屬於列印或印刷等領域,例如drawable 文件對應的就是dpi,而ppi中的pixel屬於屏幕顯示等領域
dp/dip : Density-independent Pixels,密度無關像素 - 基於屏幕物理密度的抽象單位。1dp等於 160 dpi 屏幕上的dpx,這是 系統為「中」密度屏幕假設的基線密度。在運行時,系統 根據使用中屏幕的實際密度按需要以透明方式處理 dp 單位的任何縮放 。dp 單位轉換為屏幕像素很簡單:px = dp * (dpi / 160)。 例如,在 240 dpi 屏幕上,1 dp 等於 1.5 物理像素。在定義應用的 UI 時應始終使用 dp 單位 ,以確保在不同密度的屏幕上正常顯示 UI。
如果看完文章還是覺得很懵,那麼可以直接記住: 1dp單位在設備屏幕上總是等於1/160 inch。
sp :Scale-independent Pixels ,與 dp 單位相似,也會根據用戶的字體大小偏好進行縮放。
首先我們放上源碼中對尺寸單位的轉換
可以看到,輸入值類型為dp時,返回 value * DisplayMetrics.density,到這里我們可能會發懵:嗯?不對啊,前面我們不是通過px 和 dp 的換算公式來計算的么,怎麼這里就簡簡單單乘了一個DisplayMetrics.density?不要慌,我們先看看源碼中對DisplayMetrics.density的介紹。
源碼注釋中說到「在160dpi的屏幕下,density的值為1,而在120dpi的屏幕下,density的值為0.75」,我們可以大膽的猜測一下,120dpi下的density=0.75的原因是120dpi * 1 /160dpi=0.75。實際上,也就是這么回事。我們下面會仔細的分析。
需要補充一下,通常意義上Android 屏幕的密度,指的是像素密度dpi/ppi,對應於源碼中的DisplayMetrics.densityDpi。
為什麼引入dp?
Android 引入了dp這一單位,使得不論多大屏幕,多大dpi,顯示的效果始終保持一致。
但是根據前面我們提到的px與dp的換算公式px = dp * (dpi / 160),很顯然,由於相同解析度但不同屏幕大小的設備dpi是不同的,導致px和dp的基本不存在一個固定的換算關系,為了方便屏幕適配,Android設置了6個通用的密度,換算px與dp時採取通用密度計算,而非設備實際的密度。
以下為6種通用密度,以及其最小的解析度
得到上面通用密度之後,我們換算dp與px多了一種簡便方式。前面我們提到Android將mdpi作為基準,此時1px = 1dp,又有px = dp * (dpi / 160),所以我們可以很容易的得到以下換算:
還記不記得前面源碼中的density屬性,實際上DisplayMetrics.density = dpi / 160 ,表示的就是在某個通用密度下dp與px的換算比(1dp/1px的值)
這部分其實和程序員自身已經關系不大了,畢竟參與工作之後這些都是UI人員的活兒了。不過鑒於現在我還只是一枚在校生,還是記下來以免自己遺漏吧。
建議在xhdpi中作圖
原因嘛,首先現在主流解析度是1080p,以及最近流行起來的全面屏18:9,而xhdpi對應720p,向低dpi兼容自然沒問題,即便在xxhdpi中顯示,也會有個不錯的效果。而如果以1920*1080作圖,顯然圖片素材佔用的內存很大,而且也會增大應用安裝包的大小。
只有一個原則:資源放入對應dpi的文件夾中,Android會機智的載入合適的資源。
以drawable資源為例:
我們平時開發小項目&對UI要求不高時,只使用一套xhdpi的資源就足夠了,雖然這可能會導致在hdpi及以下的手機中有些卡頓,因為xhdpi的圖片運行在hdpi及以下的手機上會比較吃內存,不過無傷大雅。
而如果不為圖片資源犯愁時(有UI人員的支持,就是任性),就可以添加所有dpi的資源。當然,重點還是要滿足ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的規律。
好像說了不少廢話,哈哈,大概就這么多吧。
㈥ 修改Android手機的解析度和屏幕密度
原文: https://blog.csdn.net/CrazyApes/article/details/116994631
之前一直不知道手機的DPI還可以修改,以前測試我都是用好幾個測試機,或者通過修改開發者模式下的最小寬度去看適配的問題。吶,前段時間朋友說可以直接用adb改,趕緊記下來,省的以後忘了。
adb 命令
wm size [reset|WxH|WdpxHdp]
return or override display size. width and height in pixels unless suffixed with 'dp'.
查看解析度: wm size
修改解析度: wm size 1440x2560
還原初設置: wm size reset
測試機: 華為 FRD-DL00
wm density [reset|DENSITY]
查看密度: wm density
修改密度: wm density 480
還原設置: wm density reset
測試機: 華為 FRD-DL00
Security exception: Must hold permission android.permission.WRITE_SECURE_SETTINGS
莫慌,打開下 開發者選項 中的 USB調試(安全設置) 就行了。
有時間可以都看一下,試一試,蠻好玩的。
說起來巧了,就像前言說的我不知道手機可以改DPI,之前一直是用的開發者模式下的最小寬度修改來測試。後來發現,這個其實也是修改了DPI,仔細想想density和px還有dp的關系,就突然能明白為啥了。
手機 開發者模式
首先得打開手機的 開發者模式 ,咋打開應該不用說了把。
不知道的小夥伴可以試著去找到你手機的 系統版本 那裡一頓狂點。
然後就有驚喜了。
比如: Redmi 9A
咱就直接進入 開發者選項 里把。
找到 繪圖 模塊下的 最小寬度 欄目。
點開之後直接輸入想要的最小寬度就行了。
注意: 這里是以 dp 為單位的。
如果你的UI設計圖的寬度跟你的手機不符,開發的時候,可以嘗試修改這個達到演示的目的。
如下: Redmi 9A
由於輸入的是寬度值,無法直觀的看到 density 的變化,但是咱們可以用方式一去驗證下,就可以看到它的變化是改了 density 的值的。
機型:Redmi 9A
可見,在 解析度 不變的前提下,修改了最小寬度之後,設備的 density 發生了變化。
Android中的dp在渲染前會將dp轉為px,計算公式:
px = density * dp;
density = dpi / 160;
px = dp * (dpi / 160);
原文: https://blog.csdn.net/CrazyApes/article/details/116994631
參考: https://developer.android.google.cn/guide/practices/screens_support
㈦ Android中常見的單位ppi,dp,dpi,sp,px
在android 開發過程中,我們使用的單位比較少,一般情況下在描述字體大小的時候我們通常用sp,而在設置間距的時候我們用dp,除此之外很少再用到其他單位,而且很多時候我們用著用著就習慣了,也不去探究為什麼這么寫,可不可以用其他單位,每個單位到底代表著什麼意思,所以說,習慣真的很可怕呀。今天,我們就來一探究竟,看看這些單位背後的含義。
像素即是屏幕上顯示數據的最基本的點,在PS裡面也是其最根本的單位,所有的圖形都是在此基礎上生成的,平時我們經常講的手機屏幕解析度就是以像素作為單位的,比如在android中我們經常說的手機像素是1080X1920,其實它所表達的意思是在該手機上面在橫向上面有1080個像素點,在縱向上有1920個像素點。
在android中用來形式字體大小的單位,正常情況下會按照手機系統設置的文本大小來顯示文字,但是同時也會與系統設置的文本保持一致,比如在有些老年機上面為了更好的操作手機有些人會將字體設置為較大字體,這個時候使用sp作為單位的字體也會隨之變大,但是如果將字體大小的單位設置為dp,則不會隨著系統字體的變化而變化。
在每次的手機廠商新品發布會上,我們都會聽到關於手機的介紹,比如手機的屏幕解析度,多大尺寸等等。而當我們知曉一個手機的屏幕分辯率和手機尺寸的時候,就可以計算出手機的物理像素密度,其計算公式為:
需要注意的是,PPI是Android手機物理像素密度,而非在Android開發過程中我們經常說到的像素密度。
屏幕密度與dpi密切相關,dpi是每英寸的點數。也就是說,密度越大,每英寸內容納的點數就越多。
在android.util包下有個DisplayMetrics類可以獲得密度相關的信息。最重要的是densityDpi這個成員,它有如下幾個常用值:
DENSITY_LOW = 120
DENSITY_MEDIUM = 160 //默認值
DENSITY_TV = 213 //TV專用
DENSITY_HIGH = 240
DENSITY_XHIGH = 320
DENSITY_400 = 400
DENSITY_XXHIGH = 480
DENSITY_XXXHIGH = 640
dpi的值主要是通過displayMetrics獲取的,獲取方式為:
val densityDpi = resources.displayMetrics.densityDpi。
dp和dip是一樣的,設備獨立像素,這個和設備硬體有關,不同設備有不同的顯示效果。而通常在做android項目的時候,為了適配市場上面眾多的手機屏幕分辯率,我們一般都會採用dp。dp是Android基於物理設備的PPI抽象出來的一個單位。它是以160dpi的屏幕為基準定義的,在160dpi的屏幕上1dp=1px,那麼由此我們就可以得出其計算公式:
換算公式:1dp = (屏幕ppi/160)px或者是px = (屏幕ppi/160)*1dp。舉個例子:假設ppi = 320,那麼1dp = 2px。
下面我們來演練一下:
如圖所示,手機的屏幕分辯率為1080X1920,尺寸為5寸,從而計算得出PPI的值為440,再通過PPI計算出1dp 約等於3px。假設現在美工給的圖上面有一個a圖標,距離頂部的距離為30px,那麼根據最終我們的換算結果可知,我們設置為10dp就可以達到完美的顯示效果。
㈧ Android中解析度,DPI,DP與PX對應關系
解析度就是手機屏幕的像素點數。一般為屏幕的「寬×高」,例如解析度有720×1280的手機設備,表示此屏幕在寬度方向有720個像素點,在高度方向有1280個像素點。
按屏幕對角測量的實際物理尺寸。為簡便起見,Android 將所有實際屏幕尺寸分組為四種通用尺寸:小、 正常、大和超大,以英寸(inch)為單位。例如有個5寸的手機設備,是指對角線的尺寸,5寸×2.54厘米/寸=12.7厘米。
就是每英寸的像素點數,數值越高當然顯示越清晰,通常 與「正常」或「高」密度屏幕相比,「低」密度屏幕在給定物理區域的像素較少。
在定義 UI 布局時應使用的虛擬像素單位,用於以密度無關方式表示布局維度 或位置。
密度無關像素等於 160 dpi 屏幕上的一個物理像素,這是 系統為「中」密度屏幕假設的基線密度。在運行時,系統 根據使用中屏幕的實際密度按需要以透明方式處理 dp 單位的任何縮放 。dp 單位轉換為屏幕像素很簡單: px = dp * (dpi / 160)。 例如,在 240 dpi 屏幕上,1 dp 等於 1.5 物理像素。在定義應用的 UI 時應始終使用 dp 單位 ,以確保在不同密度的屏幕上正常顯示 UI。
大多數情況下,確保應用中的屏幕獨立性很簡單,只需以適當的密度獨立像素( dp 單位)或 "wrap_content" 指定所有 布局尺寸值。系統然後根據適用於當前屏幕密度的縮放比例適當地縮放點陣圖可繪制對象,以 適當的大小顯示。
如上表所示,現在我們在mdpi下設計了一個48x48的應用圖標,那麼在ldip下大小縮小0.75倍為36x36,在hdip下放大1.5倍為72x72,在xhdpi下放大2倍為96x96,在xxhdpi下放大3倍為144x144,在xxxhdpi下放大4倍為192x192.
android對於不同dpi設備提供了5個目錄存放圖片,使開發人員根據實際需要對圖片適配。一般情況需要UI根據一種DPI密度、或解析度的設備設計UI,根據不同dpi的比例出圖,一般需要xhdpi、xxhdpi兩套圖,即2x、3x圖。
計算相關公式:
px = dpValue * density + 0.5f;
dp = pxValue / density + 0.5f;