ImageView中有個很重要也很常用的屬性android:scaleType
,相信大家都應該不陌生,主要用於控制圖片在ImageView中顯示的樣式,比如顯示大小、顯示位置、顯示內容區域。當然也可以在程式碼中設定:
setScaleType(ImageView.ScaleType.xxx);
ScaleType的取值一共有8種:fitCenter
,fitEnd
,center
,centerCrop
,centerInside
,matrix
,fitXY
,fitStart
。其中預設值是fitCenter。
我們先來看比較簡單的center
吧,一個60dp*40dp的ImageView(為了顯示效果,背景設成藍色)裡面放了張20dp*20dp的圖片。上圖看看效果:
center
的含義是:保持原圖的大小,顯示在ImageView的中心。當原圖的size大於ImageView的size,超過部分裁剪處理。
再來看比較“暴力”的fitXY
:
fitXY
的含義:拉伸顯示圖片,不保持原比例,填滿ImageView.嗯,果然很暴力。
嗯,接下來我們...什麼?難道你以為我要把剩下的6種樣式都貼張圖出來,然後愉快地水一篇部落格嗎?
所以接下來我放大招了,開始分析原始碼!
詳解
上面設定了這麼多種ScaleType
,那麼最終生效的位置在哪呢?答案就在 configureBounds()
方法裡,限於篇幅我貼了上面兩種樣式的法,其他的樣式實現也都類似。
private void configureBounds() {
//圖片寬高
final int dwidth = mDrawableWidth;
final int dheight = mDrawableHeight;
//Imageview寬高
final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;//
final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
final boolean fits = (dwidth < 0 || vwidth == dwidth)
&& (dheight < 0 || vheight == dheight);
if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
mDrawable.setBounds(0, 0, vwidth, vheight);
mDrawMatrix = null;
} else {
mDrawable.setBounds(0, 0, dwidth, dheight);
if (ScaleType.MATRIX == mScaleType) {//樣式應用自定義MATRIX
if (mMatrix.isIdentity()) {
mDrawMatrix = null;
} else {
mDrawMatrix = mMatrix;
}
}
if (ScaleType.CENTER == mScaleType) {
// Center bitmap in view, no scaling.
mDrawMatrix = mMatrix;
mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
Math.round((vheight - dheight) * 0.5f));
}
複製程式碼
可以看到最終的實現用到了Drawable類和Matrix類的方法。前者大家都很熟悉,就是我們設定的要顯示的圖片,而Matrix叫做矩陣,是一個專門用來處理圖形變換中的重要工具類,熟悉自定義View的同學應該對它不陌生,canvas.setMatrix(matrix)
可以做出很多獨特效果來。而我們今天的主角是ImageView
,所以沒錯imageView
也有這個方法:
imageView.setImageMatrix(matrix)
通過上述方法我們就能將自己定義的Matrix應用到ImageView中。可以看到原始碼,要使這個方法生效,ScaleType一定要設為MATRIX,不然執行完自己的變換後還是會執行樣式自己的變換,相當於沒執行。
FIT_XY
的實現很簡單,就用到了setBounds(int left, int top, int right, int bottom)
,這個四引數指的是drawable的繪製區域。
center
用到了postTranslate(float dx, float dy)
,將Drawable
移到ImageView中間,因為沒有其他處理,圖片如果比ImageView大,那麼多餘的區域就會被裁剪掉,不顯示了。
擴充
說了這麼多來個小栗子來加深理解吧: 還是上面那張圖片,scaleType設為matrix,我們再加一個按鈕,點選事件如下:
int m = 20;
//平移
private void onClick(View v) {
Matrix matrix = new Matrix();
matrix.postTranslate(m, m);
imageView.setImageMatrix(matrix);
m = m + 3;
}
複製程式碼
來看看效果:
通過改變postTranslate
引數的值我們就能改變圖片在View中繪製的起始位置。
當然不會這麼簡單。Matrix還有其他方法:
postRotate(float degrees, float px, float py)
//旋轉:
我們仿照center的處理將圖片移到ImageView中心,然後進行旋轉:
int m = 20;
//旋轉
private void onClick(View v) {
Matrix matrix = new Matrix();
int width = imageView.getDrawable().getIntrinsicWidth();
int height = imageView.getDrawable().getIntrinsicHeight();
final int vwidth = imageView.getWidth();
final int vheight = imageView.getHeight();
matrix.setTranslate(Math.round((vwidth - width) * 0.5f),
Math.round((vheight - height) * 0.5f));
matrix.postRotate(m, vwidth * 0.5f, vheight * 0.5f);
imageView.setImageMatrix(matrix);
m = m + 3;
}
複製程式碼
看看效果:
還有一種是錯切,將圖片的形狀改變:
void setSkew(float kx, float ky)
實際用到的比較少,就不貼程式碼了,直接看效果吧:
總結
說了這麼多,這篇文章就是給大家介紹了android:scaleType
的自定義用法,當遇到Imageview預設的顯示模式不能滿足我們現有需求的時候(比如我就遇到原圖按照原來的大小居底部顯示,如果原圖的大小超過了ImageView的大小,那麼就剪裁掉多餘部分,保留底部,和centerCrop裁剪四周有所不同),我們就可以動態設定自己的matrix來自定義顯示效果。當然如果你經常要用到這種方式的時候,可以繼承Imageview,封裝這些自定義樣式。