在屏幕邊緣顯示一張圖片,超出屏幕寬度時,只顯示圖片的左邊部分,而且不被擠壓,其他部分剪切。但我在實際開發中,踩了個坑,這裏作個記錄,下面經過圖片直觀瞭解一下狀況:php
理想 | 現實 |
---|---|
目前能夠肯定,這種狀況會出如今使用RelativeLayout做爲ImageView父控件的狀況下,其餘類型的ViewGroup效果如何,暫不肯定。java
這部分是我對問題研究的記錄,心急的朋友能夠直接跳到第三部分,看源碼實現。android
在網上也百度到了一個相似的問題: Android ImageView 超出屏幕邊界 圖片會被擠壓app
這位朋友遇到的問題跟我是差很少的,當子控件ImageView超過父控件尺寸時,ImageView顯示的圖片就會擠壓,熱心的網友們給他支了一個招:把ImageVIew放在HorizontalScrollView控件裏面。可是,我遇到的需求是不要滾動效果(不要跟我說能夠屏蔽ScrollView滾動。。。),就單單顯示圖片的部分區域而已,使用HorizontalScrollView控件明顯不適用,只能另尋出路了。ide
實踐證實,使用LinearLayout做爲ImageView的父控件,當ImageView超出父控件尺寸時,不會擠壓圖片。函數
這種方式是一種不錯的解決方案,可是,侷限性太大,大多數狀況下,會但願使用RelativeLayout做爲控件的父控件,因此,這種狀況也不適用我目前的狀況。源碼分析
由於前面的方案都要求將ImageView放置到特定父控件中,侷限性太大,嚴重的,可能會形成UI屢次繪製,下降性能,形成畫面卡頓,因此,感受仍是從ImageView自己下手比較合理。佈局
ImageView的ScaleType有以下幾種:post
縮放模式 | 裁剪 | 按比例 | 放大 | 縮小 | 描述 |
---|---|---|---|---|---|
MATIRX | 未知 | 未知 | 未知 | 未知 | 經過設定setImageMatrix函數相應的矩陣,來完成。 |
FIT_XY | 否 | 否 | 是 | 是 | 直接將圖片鋪滿整個view |
CENTER | 是 | 是 | 否 | 否 | 1)若是圖片較小,直接居中所有顯示2) 若是圖片較大,裁剪後居中顯示 |
CENTER_CROP | 是 | 是 | 是 | 是 | 按比例縮放,按照縮放比例大的進行縮放,而後居中顯示(除非圖片和view的形狀同樣,不然必定存在裁剪,因此有的描述爲圖片的長寬≥View的長寬) |
CENTER_INSIDE | 否 | 是 | 否 | 是 | 1) 若是圖片較小,直接放入view,不進行放大處理,居中顯示2) 將圖片按比例進行縮放,使得圖片徹底展現,而且長或者寬等於view的長和寬(因此有的描述爲圖片的長寬≤View的長寬) |
FIT_START | 否 | 是 | 是 | 是 | 對圖片的處理和FIT_CENTER,區別爲:1)view的橫向有空,居左邊2)view的縱向有空,居上邊 |
FIT_CENTER(默認) | 否 | 是 | 是 | 是 | 將圖片按比例進行縮放,使得圖片徹底展現,而且長或者寬等於view的長和寬(因此有的描述爲圖片的長寬≤View的長寬),最後居中顯示 |
FIT_END | 否 | 是 | 是 | 是 | 對圖片的處理和FIT_CENTER,區別爲:1) view的橫向有空,居右邊2) view的縱向有空,居下邊 |
經過上表描述,能夠肯定只有CENTER_CROP的效果比較符合,但仍是有點區別,CENTER_CROP只會顯示中間區域部分,而我要的是顯示左邊區域,因此,下面就進行ImageView源碼分析。
在ImageView中搜索CENTER_CROP,定位到核心邏輯就在configureBounds()方法中,代碼以下:
如下是 博客:ImageView的ScaleType原理及效果分析 中對CENTER_CROP的解釋。
該模式按比例擴大圖片的尺寸並居中顯示,使得圖片長(寬)等於或大於View的長(寬)。
若是dwidth/dheight>vwidth/vheight(圖片的寬高比大於ImageView的寬高比),即vheight/dheight>vwidth/dwidth,也就是說ImageView和圖片高度比小於ImageView和圖片的寬度比,這時候取vheight/dheight的比例進行圖片縮放,這樣就能保證圖片寬度在進行同等比例縮放的時候,圖片寬度大於或等於ImageView的寬度,由於(vheight/dheight)* dwidth>vwidth。
同理,若是vwidth/dwidth>vheight/dheight時,取vwidth/dwidth做爲圖片的縮放比例,能夠保證縮放完成後圖片寬度等於ImageView的寬度,圖片的高度大於或等於ImageView的高度,由於(vwidth/dwidth)*dheight>vheight。圖片在縮放以後再進行CENTER操做便可。
上圖所示,vwidth/dwidth>vheight/dheight,圖片先按照vwidth/dwidth進行縮放,縮放後的圖片高度>=vheight,而後再進行向上移位。
上圖所示,vheight/dheight>vwidth/dwidth,圖片先按照vheight/dheight進行縮放,縮放後的圖片寬度>=vwidth,而後再進行想左移位。
回到主線,根據上面的分析,明白了CENTER_CROP的工做原理(可能也不太明白,但不要緊),咱們只須要在CENTER_CROP的基礎上控制dx或dy便可,同時,在分析完整個configureBounds()方法以後,能夠肯定,不論是哪一種ScaleType,其原理都是操控圖片矩陣mDrawMatrix來實現的,這時候ScaleType中的MATRIX就能夠派上用場了,下面是我對MATRIX作的一些封裝,你也能夠根據本身的項目需求,編寫本身的處理邏輯。
用了在佈局中使用方便,我將它作成一個自定義控件,命名爲ImageViewExt。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ImageViewExt">
<attr name="ive_scale_type_matrix_ext" format="enum">
<enum name="left_crop" value="1"/>
<enum name="right_crop" value="2"/>
<enum name="center_crop" value="3"/>
</attr>
</declare-styleable>
</resources>
複製代碼
/** * @建立者 CSDN_LQR * @時間 2018/9/4 * @描述 ImageView擴展控件 * <p> * 一、對 ScaleType.MATRIX 進行封裝拓展 */
public class ImageViewExt extends ImageView {
public static final int SCALE_TYPE_MATRIX_LEFT_CROP = 1; // 等比例縮放,當圖像超出控件尺寸時,保留左邊,其他部分剪切掉。
public static final int SCALE_TYPE_MATRIX_RIGHT_CROP = 2; // 等比例縮放,當圖像超出控件尺寸時,保留右邊,其他部分剪切掉。
public static final int SCALE_TYPE_MATRIX_CENTER_CROP = 3; // 等比例縮放,當圖像超出控件尺寸時,保留中間,其他部分剪切掉。
@IntDef({SCALE_TYPE_MATRIX_LEFT_CROP, SCALE_TYPE_MATRIX_RIGHT_CROP, SCALE_TYPE_MATRIX_CENTER_CROP})
@Retention(RetentionPolicy.RUNTIME)
public @interface ScaleTypeMatrixExt {
}
private int mScaleTypeMatrixExt;
public ImageViewExt(Context context) {
this(context, null);
}
public ImageViewExt(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ImageViewExt(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
protected void init(Context context, @Nullable AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ImageViewExt);
mScaleTypeMatrixExt = typedArray.getInt(R.styleable.ImageViewExt_ive_scale_type_matrix_ext, -1);
typedArray.recycle();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
handScaleTypeMatrixExt();
}
@Override
public void requestLayout() {
super.requestLayout();
handScaleTypeMatrixExt();
}
private void handScaleTypeMatrixExt() {
if (this.getScaleType() == ScaleType.MATRIX && mScaleTypeMatrixExt != -1) {
// 圖片實際尺寸
final int dwidth = getDrawable().getIntrinsicWidth();
final int dheight = getDrawable().getIntrinsicHeight();
// ImageView圖片顯示尺寸
final int vwidth = getWidth() - getPaddingLeft() - getPaddingRight();
final int vheight = getHeight() - getPaddingTop() - getPaddingBottom();
float scale;
float dx = 0, dy = 0;
if (dwidth * vheight > vwidth * dheight) { // 圖片寬高比 > 控件寬高比
scale = (float) vheight / (float) dheight;
switch (mScaleTypeMatrixExt) {
case SCALE_TYPE_MATRIX_LEFT_CROP:
dx = 0; // 保留左邊
break;
case SCALE_TYPE_MATRIX_RIGHT_CROP:
dx = (vwidth - dwidth * scale); // 保留右邊
break;
case SCALE_TYPE_MATRIX_CENTER_CROP:
dx = (vwidth - dwidth * scale) * 0.5f; // 保留中間(效果與 CENTER_CROP 同樣)
break;
default:
break;
}
} else {
scale = (float) vwidth / (float) dwidth;
// dy = (vheight - dheight * scale) * 0.5f; // 根據實際狀況編寫,默認爲0,保留上邊
}
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
matrix.postTranslate(Math.round(dx), Math.round(dy));
this.setImageMatrix(matrix);
}
}
public void setScaleTypeMatrixExt(@ScaleTypeMatrixExt int scaleTypeMatrixExt) {
this.mScaleTypeMatrixExt = scaleTypeMatrixExt;
requestLayout();
}
}
複製代碼
須要使用matrix做爲ImageView的ScaleType,再指定ive_scale_type_matrix_ext屬性便可,也能夠在代碼中調用setScaleType()、setScaleTypeMatrixExt()來指定。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="382.5dp" android:background="@android:color/white" android:orientation="horizontal">
<com.lqr.widget.ImageViewExt android:layout_width="275dp" android:layout_height="135.5dp" android:layout_marginLeft="450dp" android:scaleType="matrix" android:src="@mipmap/main_recommand_1_4_sample3" app:ive_scale_type_matrix_ext="left_crop"/>
</LinearLayout>
複製代碼
效果以下: