平常開發中咱們少不了要根據設計圖繪製UI,通常而言設計師給的都是設計圖都是750*1334
的,給的切圖也通常是2x
、3x
圖。html
簡單起見,咱們只將對應的2x
圖標放到res/drawable-xhdpi
目錄下便可。java
固然了,對於要求高的圖標,咱們須要添加對應的多套圖,分別放置到drawable-mdpi
、drawable-hdpi
、drawable-xhdpi
、drawable-xxhdpi
、drawable-xxxhdpi
、目錄下。android
ps: `drawable-ldpi`過低了,能夠忽略掉。
複製代碼
圖標的容器咱們通常使用ImageView,代碼以下:git
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/empty_icon" />
複製代碼
實際開發中咱們直接給對應的src屬性設置對應的圖片資源id便可,不一樣機型上的適配工做,Android系統會自動幫咱們完成。github
系統會自動根據當前機型的dpi,到對應的drawable目錄下獲取圖片,接着再對圖片進行適當的縮放操做,最後完成顯示。bash
關於dpi和drawable是如何匹配的,請移步郭霖大神的Android drawable微技巧,你所不知道的drawable的那些細節。app
這篇文章中有一個很重要的dpi匹配的表,以下:ide
這裏我想講下Android在獲取到對應的圖片後,是如何進行對應的縮放操做的。工具
咱們先從一個例子講起。post
咱們先準備對應的五張圖片 empty_icon
,他們的分辨率分別是
mdpi 106*106
hdpi 159*159``
xhdpi 213*213
xxxhdpi 319*319
xxxhdpi 426*426
複製代碼
咱們看下官網的說明,以下圖:
這說明咱們的圖片是符合比例規則的,接着將他們放入到對應的drawable目錄下。
ps:這幾張圖片來自於bravh這個庫,若有侵權,請聯繫我,侵刪。
接着咱們將這個圖片設置給ImageView對象,代碼以下:
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/empty_icon" />
複製代碼
而後獲取當前圖片的實際寬高,代碼以下:
iv.post {
var sb = StringBuffer("圖片實際寬高:\n")
sb.append("width: " + iv.width)
sb.append("\n")
sb.append("height: " + iv.height)
tvIvInfo.text = sb.toString()
}
複製代碼
接着運行代碼,咱們看下現象,效果圖以下:這個測試機的dpi爲440。
咦,這裏圖片的尺寸怎麼不對呢?drawable-xxhdpi文件夾下的圖片尺寸命名是319
啊,這裏爲什麼不一致,並且咱們也沒有這個尺寸的圖片啊,爲何呢?
莫慌,咱們此次換一個xxhdpi的模擬器試下,運行效果以下圖:
此次效果正確了吧,但是這個縮放原理是什麼呢?
咱們都知道Android會爲咱們自動縮放drawable中的圖片,但是到底縮放了多少,什麼狀況下縮放呢?
咱們先看下dpi和drawable的對應關係:須要說明的是,這裏的範圍都是不包含頭包含尾
,能夠用(a,b]
來表示。
咱們第一次運行的測試機的dpi爲440,第二次的爲480,他兩對應的dpi等級均是xxhdpi
,因此它們對應的drawable目錄爲drawable-xxhdpi
,咱們這裏對應的圖片的尺寸應該是319*319
。
但是爲啥兩個手機上顯示的尺寸不同呢?一個是292*292
,一個是319*319
。有什麼規律呢?
眼尖的同窗應該已經看出來了,實際的圖片尺寸
的縮放比例
跟實際dpi
和對應dpi等級
相關,規律以下:
對第一個實例來講,實際dpi
這裏對應的分別是440,對應的dpi
經過上面的表格能夠得出爲480,對應drawable圖片尺寸
爲319px,實際顯示尺寸
爲咱們獲取到的292.
上述公式轉換下,以下所示:計算實際顯示尺寸的值。
針對某個圖片來講,實際dpi
、對應的dpi等級
、對應drawable下圖片尺寸
這三個值都是已知的,根據這三個值咱們就能夠獲取到實際顯示的尺寸。
接下來咱們驗證下咱們這個結論。咱們先寫一個工具類,根據實際dpi
獲取對應的dpi等級
,代碼以下所示:
/**
* 根據實際dpi獲取對應的dpi等級。
* 登記表參見 https://blog.csdn.net/guolin_blog/article/details/50727753
* @param srcDpi
* @return
*/
public static int getTargetDpi(int srcDpi) {
int targetDpi = 0;
if (srcDpi <= 120) {// ldpi
targetDpi = 120;
} else if (srcDpi <= 160) {// mdpi
targetDpi = 160;
} else if (srcDpi <= 240) {// hdpi
targetDpi = 240;
} else if (srcDpi <= 320) {// xhdpi
targetDpi = 320;
} else if (srcDpi <= 480) {// xxhdpi
targetDpi = 480;
} else if (srcDpi <= 640) {// xxxhdpi
targetDpi = 640;
}
return targetDpi;
}
複製代碼
接着咱們再寫一個方法,根據對應的dpi等級,能夠獲取 R.drawable.empty_icon 的實際尺寸:
/**
* 根據對應的dpi等級,獲取 R.drawable.empty_icon 對應的實際尺寸
*/
fun getDrawableSize(targetDpi: Int): Int {
var drawableSize = 0;
when (targetDpi) {
120, 160 -> drawableSize = 106
240 -> drawableSize = 159
320 -> drawableSize = 213
480 -> drawableSize = 319
640 -> drawableSize = 426
}
return drawableSize
}
複製代碼
接下來就是核心代碼了,以下所示:
// 獲取當前手機實際的dpi
var srcDpi = this.resources.displayMetrics.densityDpi
// 獲取實際dpi對應的dpi等級
var targetDpi = ScreenUtils.getTargetDpi(srcDpi)
// 根據dpi等級,獲取 R.drawable.empty_icon 實際尺寸
var drawableSize = getDrawableSize(targetDpi)
// 根據實際尺寸計算縮放後的尺寸
var resultSize = drawableSize * 1.0f / targetDpi * srcDpi
tvExpect.text = String.format("指望結果:%.2f", resultSize)
複製代碼
咱們先在剛纔的440dpi的手機上驗證下,效果以下:
能夠看出,咱們計算出的指望值
,四捨五入
後就是實際顯示的值。
接下來看下mdpi的手機上的顯示效果:
接下來看下hdpi的手機上的顯示效果:
接下來看下xhdpi的手機上的顯示效果:
接下來看下420hdpi的手機上的顯示效果:
接下來看下440hdpi的手機上的顯示效果:
接下來看下xxhdpi的手機上的顯示效果:
接下來看下560hdpi的手機上的顯示效果:
因爲Android Studio自帶的模擬器中沒有xxxhdpi等級的模擬器,因此這裏就只能使用560dpi近似展現了,他兩是一個dpi等級的。
經過上述分析,咱們之後能夠放心的使用Android自帶的drawable文件進行圖標的適配了,只要咱們正確的提供了多套圖,Android系統會自動爲咱們加載合適的圖片,再進行適當的縮放。
以前不是很懂這個原理的時候,我都是經過給ImageView設置高度來適配的,代碼以下:
<ImageView
android:id="@+id/iv"
android:layout_width="106dp"
android:layout_height="106dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/empty_icon" />
複製代碼
此次搞清楚原理以後,這種比較苟的方式就能夠廢棄了,直接使用Android提供的默認方式便可,這樣ImageView的書寫方式就極其簡單了:
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/empty_icon" />
複製代碼
具體demo地址位於: github.com/tinyvampire…
打開方式以下: