Android加載drawable中圖片後自動縮放的原理

Android加載drawable中圖片後自動縮放的原理

平常開發中咱們少不了要根據設計圖繪製UI,通常而言設計師給的都是設計圖都是750*1334的,給的切圖也通常是2x3x圖。html

簡單起見,咱們只將對應的2x圖標放到res/drawable-xhdpi目錄下便可。java

固然了,對於要求高的圖標,咱們須要添加對應的多套圖,分別放置到drawable-mdpidrawable-hdpidrawable-xhdpidrawable-xxhdpidrawable-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" />
複製代碼

github項目地址

具體demo地址位於: github.com/tinyvampire…

具體頁面:github.com/tinyvampire…

打開方式以下:

參考

Android drawable微技巧,你所不知道的drawable的那些細節

developer.android.com/guide/topic…

相關文章
相關標籤/搜索