ImageView中ScaleType屬性可用來設置image的填充方式,主要通過以下兩種途徑:1、XML文件中設置Android:scaleType屬性。2、代碼中使用函數setScaleType(ScaleType scaleType)來設定。目前內置的填充方式有如下8種:
CENTER /center 按圖片的原來size居中顯示,當圖片長/寬超過View的長/寬,則截取圖片的居中部分顯示
CENTER_CROP / centerCrop 按比例擴大圖片的size居中顯示,使得圖片長(寬)等於或大於View的長(寬)
CENTER_INSIDE / centerInside 將圖片的內容完整居中顯示,通過按比例縮小或原來的size使得圖片長/寬等於或小於View的長/寬
FIT_CENTER / fitCenter 把圖片按比例擴大/縮小到View的寬度,居中顯示
FIT_END / fitEnd 把圖片按比例擴大/縮小到View的寬度,顯示在View的下部分位置
FIT_START / fitStart 把圖片按比例擴大/縮小到View的寬度,顯示在View的上部分位置
FIT_XY / fitXY 把圖片不按比例 擴大/縮小到View的大小顯示
MATRIX / matrix 用矩陣來繪制首先要選擇設定圖片填充方式的時機,不管如何,我們在必須在draw之前設定填充方式,因此我們可以考慮在layout的時候,通過查看layout源碼,注意到setFrame函數,setFrame主要是設定view的尺寸和位置,並返回view是否changed,因此可在setFrame中設定填充方式,layout代碼片段如下:
- public void layout(int l, int t, int r, int b) {
- int oldL = mLeft;
- int oldT = mTop;
- int oldB = mBottom;
- int oldR = mRight;
- boolean changed = setFrame(l, t, r, b);
- if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);
- }
- onLayout(changed, l, t, r, b);
然而對於人像為主的圖片來說,默認的幾種方式都無法很好的滿足需求,因為人像的頭部往往被切割了,我們可以忍受人像下半部分被切割,但是無法忍受頭部被切割,因此我們考慮第9種填充方式:TOP_CROP,TOP_CROP按如下方式填充圖片:按比例擴大圖片的size,僅僅橫向居中,使得圖片長(寬)等於或大於View的長(寬)。對於CENTER_CROP,其不僅橫向居中,而且垂直也居中。
具體實現方式:重載ImageView,並重寫setFrame方法來對ImageView中的drawable進行變換,代碼如下:
- public class TopCropImageView extends ImageView {
-
- public TopCropImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- setScaleType(ScaleType.MATRIX);
- }
-
- public TopCropImageView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- setScaleType(ScaleType.MATRIX);
- }
-
- public TopCropImageView(Context context) {
- super(context);
- setScaleType(ScaleType.MATRIX);
- }
-
- @Override
- protected boolean setFrame(int l, int t, int r, int b)
- {
- if (getDrawable() == null) {
- return super.setFrame(l, t, r, b);
- }
- Matrix matrix = getImageMatrix();
- float scaleWidth = getWidth()/(float)getDrawable().getIntrinsicWidth();
- float scaleHeight = getHeight()/(float)getDrawable().getIntrinsicHeight();
- float scaleFactor = (scaleWidth > scaleHeight) ? scaleWidth : scaleHeight;
- matrix.setScale(scaleFactor, scaleFactor, 0, 0);
- if (scaleFactor == scaleHeight) {
- float tanslateX = ((getDrawable().getIntrinsicWidth() * scaleFactor) - getWidth()) / 2;
- matrix.postTranslate(-tanslateX, 0);
- }
- setImageMatrix(matrix);
- return super.setFrame(l, t, r, b);
- }
- }
代碼中首先計算ImageView尺寸和Drawable尺寸的比值,用變量scaleWidth和scaleHeight保存,並用scaleFactor取兩者較大值,因為我們要滿足圖片長(寬)等於或大於View的長(寬),然後調用matri.setScale進行圖片的縮放操作,接下來的if (scaleFactor == scaleHeight) 的含義是Drawable放大後的width大於ImageView的width,這意味著我們需要進行水平居中平移,if分支中的代碼即實現了平移操作,最後通過setImageMatrix(matrix)將matrix應用到image中來實現TOP_CROP的填充方式。下面兩張圖顯示了CENTER_CROP和TOP_CROP的不同效果: