原文:Working with the ImageViewcss
ImageView 有一個常用場景:ImageView 的寬度固定,高度等比例縮放。且 ImageView 在 padding 全部爲 0 的狀況下不留白邊,即圖片全然填充 ImageView。(注意:該方法對「高度固定,寬度等比例縮放」不適用,詳細見 例1-2 代碼)html
這篇文給出了這個場景的答案,翻譯過來以背不時之需。java
上述需求可以用例如如下屬性實現:
例1-1android
<ImageView android:id="@+id/image" android:layout_width="30dp" android:layout_height="wrap_content" android:scaleType="fitXY" android:adjustViewBounds="true" android:src="@drawable/image" />
但是,例如如下代碼是不行的,顯示的圖片可能會出現變形,變形的圖片寬度爲原始圖片的寬度,而高度被強制縮放成「30dp」:
例1-2git
<ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="30dp" android:scaleType="fitXY" android:adjustViewBounds="true" android:src="@drawable/image" />
或者用 BitmapScaler 這個工具類。相關方法例如如下:github
public class BitmapScaler
{
// Scale and maintain aspect ratio given a desired width
// BitmapScaler.scaleToFitWidth(bitmap, 100);
public static Bitmap scaleToFitWidth(Bitmap b, int width)
{
float factor = width / (float) b.getWidth();
return Bitmap.createScaledBitmap(b, width, (int) (b.getHeight() * factor), true);
}
// Scale and maintain aspect ratio given a desired height
// BitmapScaler.scaleToFitHeight(bitmap, 100);
public static Bitmap scaleToFitHeight(Bitmap b, int height)
{
float factor = height / (float) b.getHeight();
return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factor), height, true);
}
// ...
}
通常來講,咱們使用 SDK 內置的圖片控件展現圖片。這個圖片控件會本身考慮載入和優化問題。使得開發人員不少其它的考慮應用相關的佈局和內容等細節。markdown
這篇教程中,咱們將逐一解說怎樣使用 ImageView,怎樣操做 bitmap,各類分辨率的目錄以及其它內容。app
從最簡單的開始,ImageView 是佈局文件裏的一個控件。用途是在屏幕中展現圖片(或 drawable 資源文件)。ide
用法大概例如如下:svg
<ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="center" android:src="@drawable/my_image" />
ImageView 會爲你處理全部的載入和縮放問題。注意,scaleType 屬性決定圖片圖片怎樣縮放以適應你的佈局。在上例中,scaleType = 「center」 使得圖片以原始分辨率和居中的方式展現,而不考慮控件佔用多大的空間。
一般條件下,ImageView 要控制的對象是圖片的寬高,即 layout_width 和 layout_height:
<ImageView android:layout_width="50dp" android:layout_height="50dp" android:scaleType="fitXY" />
樣例中的 scaleType=」fitXY」 表示將寬高均縮放到指定的長度「50dp」。
Fixing the width and height however means that the proportions of the width and height of the original image, known as the aspect ratio, will be altered. We can take advantage of the adjustViewBounds parameter to preserve this aspect ratio. However, we must either allow the height and/or width to be adjustable (i.e. by using maxWidth and using wrap_content for the dimension). Otherwise, the dimensions cannot be readjusted to meet the required aspect ratio.
然而,固定的寬高會改變原始圖片的寬高比,而使用 adjustViewBounds 參數可以保持寬高比。必須將寬度或高度設置爲可調節的(好比使用 maxWidth 和 wrap_content)。不然沒法保持原始圖片的寬高比。
<ImageView android:layout_width="50dp" android:layout_height="wrap_content" android:scaleType="fitXY" android:adjustViewBounds="true" />
經過這樣的將各類屬性組合使用的方式咱們可以控制圖片的大體尺寸和寬高比例。
一樣咱們可以用 Java 代碼經過 getLayoutParams() 動態的更改 ImageView 的寬高:
imageView.getLayoutParams().height = 100; // OR
imageView.getLayoutParams().width = 100;
某些場景下,圖片需要縮放以適應父view的寬度。同一時候要求圖片高度等比例縮放。
咱們可以使用連接中的 ResizableImageView 來達到目的。
ImageView 依據 scaleType 的類型來展現圖片。
上文中咱們探討了 fitXY 和 adjustViewBounds。如下是常用的 scaleType 的一覽表:
(注意:
scaleType | 描寫敘述 |
---|---|
center | 將圖片中心與 ImageView 的中心重合,保持圖片的原始尺寸,僅僅顯示落在 ImageView 內部的圖片部分 |
centerCrop | 將圖片中心與 ImageView 的中心重合,而後進行等比例縮放。直到圖片寬高均不小於 ImageView 的寬高,位於 ImageView 以外的圖片部分不顯示,縮放過程當中保持圖片寬高比 |
centerInside | 將圖片中心與 ImageView 的中心重合,假設圖片全部位於 ImageView 內部,則完畢,不然對圖片等比例縮小直到圖片寬高均不大於 ImageView 的寬高 |
fitCenter | 將圖片中心與 ImageView 的中心重合。而後等比例進行縮放,直到圖片寬高均不大於 ImageView 的寬高;fitCenter 與 centerInside 的差異在於:當圖片原始尺寸小於 ImageView 時,後者不正確圖片作不論什麼處理而前者對圖片進行等比例放大直至其寬高至少有一項與 ImageView 相應的寬高相等 |
fitStart | 將圖片左上角與 ImageView 的左上角重合。其他和 fitCenter 一樣 |
fitEnd | 將圖片右下角與 ImageView 的右下角重合,其他和 fitCenter 一樣 |
fitXY | 將圖片的寬高縮放到與 ImageView 的寬高全然一樣;縮放過程全然無視原始圖片的寬高比 |
matrix | 依據 setImageMatrix() 方法設置的 Matrix 類來顯示圖片,Matrix 類可以用來實現圖片翻轉等效果 |
上圖相應的 android:scaleType 值:
第一行(從左至右)依次是 center, centerCrop, centerInside;
第二行(從左至右)依次是 fitCenter, fitStart, fitEnd, fitXY。
由上述圖表可以看出,scaleType 可分爲 3 大類:center,fit。matrix:
scaleType | 圖片和ImageView中心點重合 | 保持圖片原始尺寸 | 保持圖片寬高比 | 顯示圖片與 ImageView 大比較 |
---|---|---|---|---|
center | √ | √ | √ | 同圖片原始尺寸和 ImageView 大小關係 |
centerCrop | √ | x | √ | >= |
centerInside | √ | x | √ | <= |
fitCenter | √ | x | √ | <= |
fitStart | x | x | √ | <= |
fitEnd | x | x | √ | <= |
fitXY | √ | x | x | = |
還不明確?看下視頻解說吧:安卓 ImageView scaleType 屬性值解析
因爲安卓設備的屏幕尺寸、分辨率類型繁雜,需要有一個能本身主動爲設備匹配合適的資源的強大系統。安卓project目錄和安裝包中有專門爲不一樣類型的設備準備的資源目錄,包含:ldpi(低分辨率)。mdpi(medium dots per inch。中分辨率),hdpi(高分辨率)。xhdpi(超高分辨率)。這些資源目錄以 drawable-mdip 的形式命名。
爲了適配多種分辨率,咱們要依照 3:4:6:8 的比例來爲上述資源目錄設計圖片文件。詳細例如如下:
分辨率 | DPI | 演示樣例設備 | 換算比例 | 像素 | 備註 |
---|---|---|---|---|---|
ldpi | 120 | Galaxy Y | 0.75x | 1dp = 0.75px | |
mdpi | 160 | Galaxy Tab | 1.0x | 1dp = 1px | |
hdpi | 240 | Galaxy S II | 1.5x | 1dp = 1.5px | |
xhdpi | 320 | Nexus 4 | 2.0x | 1dp = 2px | 720p |
xxhdpi | 480 | Nexus 5 | 3.0x | 1dp = 3px | 1080p |
xxxhdpi | 640 | Nexus 6 | 4.0x | 1dp = 4px |
這意味着。假設你在 drawable-mdpi 目錄中有一張 100x100 的圖片。那麼你要在 drawable-ldpi 文件裏放置 75x75 的圖片,drawable-hdpi 文件裏放置 150x150 的圖片,在 drawable-xhdpi 中放置 200x200的。在 drawable-xxhdpi 中放置 300x300 的圖片。
Final Android Resizer 可以讓你方便的對圖片進行縮放:
這個便捷的工具可以讓咱們選擇 drawable-xxhdpi 目錄中的一張圖片,本身主動的在相應的分辨率的資源目錄中生成相應分辨率的圖片。
不少其它支持多分辨率的知識請移步安卓支持多屏幕和圖標設計官方文檔。
從 4.3 系統開始,安卓提供一個 res/mipmap 的目錄,用來存儲紋理圖片。紋理最大的用處是應用圖標,如啓動圖標等。關於紋理的優勢請移步這篇博文:紋理資源文件。
紋理圖片資源經過 @mipmap/ic_launcher 的方式引用。將圖標放在 res/mipmap 目錄(而不是 drawable 目錄)是最優的做法,因爲這些圖標會在與其它分辨率下常用。
For example, an xxxhdpi app icon might be used on the launcher for an xxhdpi device. Review this post about preparing for the Nexus 6 which explains in more detail。
咱們可以在 Java 代碼中設置 ImageView 展現的圖片:
ImageView image = (ImageView) findViewById(R.id.test_image);
image.setImageResource(R.drawable.test2);
或者:
ImageView image = (ImageView) findViewById(R.id.test_image);
Bitmap bMap = BitmapFactory.decodeFile("/sdcard/test2.png");
image.setImageBitmap(bMap);
你可以調用 createScaleBitmap() 方法來調整 Bitmap 的尺寸:
// Load a bitmap from the drawable folder
Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
// Resize the bitmap to 150x100 (width x height)
Bitmap bMapScaled = Bitmap.createScaledBitmap(bMap, 150, 100, true);
// Loads the resized Bitmap into an ImageView
ImageView image = (ImageView) findViewById(R.id.test_image);
image.setImageBitmap(bMapScaled);
假設要等比例縮放 Bitmap。可以用 BitmapScaler 這個工具類,代碼例如如下:
public class BitmapScaler
{
// Scale and maintain aspect ratio given a desired width
// BitmapScaler.scaleToFitWidth(bitmap, 100);
public static Bitmap scaleToFitWidth(Bitmap b, int width)
{
float factor = width / (float) b.getWidth();
return Bitmap.createScaledBitmap(b, width, (int) (b.getHeight() * factor), true);
}
// Scale and maintain aspect ratio given a desired height
// BitmapScaler.scaleToFitHeight(bitmap, 100);
public static Bitmap scaleToFitHeight(Bitmap b, int height)
{
float factor = height / (float) b.getHeight();
return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factor), height, true);
}
// ...
}
其它場景下,你可能想要依據屏幕的高或寬來縮放圖片。將 DeviceDimensionsHelper.java 這個工具類複製到你的project中,而後在 Context 中使用例如如下代碼:
// Get height or width of screen at runtime
int screenWidth = DeviceDimensionsHelper.getDisplayWidth(this);
// Resize a Bitmap maintaining aspect ratio based on screen width
BitmapScaler.scaleToFitWidth(bitmap, screenWidth);
關於這個工具類的不少其它知識請戳我。
注意:不論什麼形式的圖片縮放都會形成圖片 EXIF 元數據的丟失,包含相機。旋轉。拍攝時間等。儘管有解決方式能將這些數據轉移,但現在仍然有缺陷。假設你需要這些元數據或者想連同元數據一塊兒上傳到server,那麼你應該上傳原始文件而非處理後的文件。
經過 svg-android 這個第三方庫咱們可以使用屏幕分辨率無關的 SVG 圖片。
// Parse an SVG resource from the "raw" resource folder
SVG svg = SVGParser.getSVGFromResource(getResources(), R.raw.android);
// Fix issue with renderer on certain devices
myImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
// Get a drawable from the parsed SVG and set it as the drawable for the ImageView
myImageView.setImageDrawable(svg.createPictureDrawable());
不少其它知識詳見官方文檔。