在开发过程中,用于显示图片大家用的比较多的应该是ImageView,在显示图片时是通常我们会设置scaleType以达到不同的展示效果。然后通常scaleType能设置的属性仅为:
- 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 用矩阵来绘制,动态缩小放大图片来显示。
但是如果我们想达到scaleType为CENTER_CROP类型的展示图片方式且左对齐时,就感觉很无力了,ImageView并没有提供这个类型。
这时我们通过查看ImageView源码中处理scaleType为CENTER_CROP的逻辑,源码如下:
private void configureBounds() {
if (mDrawable == null || !mHaveFrame) {
return;
}
final int dwidth = mDrawableWidth;
final int dheight = mDrawableHeight;
final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
final boolean fits = (dwidth < 0 || vwidth == dwidth)
&& (dheight < 0 || vheight == dheight);
...
if (ScaleType.CENTER_CROP == mScaleType) {
mDrawMatrix = mMatrix;
float scale;
float dx = 0, dy = 0;
if (dwidth * vheight > vwidth * dheight) {
scale = (float) vheight / (float) dheight;
dx = (vwidth - dwidth * scale) * 0.5f;
} else {
scale = (float) vwidth / (float) dwidth;
dy = (vheight - dheight * scale) * 0.5f;
}
mDrawMatrix.setScale(scale, scale);
mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
}
...
}
}
可知,它的计算公式,那我们就通过外部设置matrix的方式来达到这种效果。
具体步骤如下:
- 1、设置android:scaleType=“matrix”,它的图片呈现效果前文已做解释
- 2、设置图片加载加载成功的监听,这里我使用的是Glide,代码如下:
Glide.with(mContext)
.load(tempImageUrl)
.placeholder(R.drawable.a_theme_banner_top_bg)
.error(R.drawable.a_theme_banner_top_bg)
.listener(mRequestListener)
.dontAnimate()
.into(imageView);
其中mRequestListener的代码为:
private RequestListener mRequestListener=new RequestListener<Object, GlideDrawable>() {
@Override
public boolean onException(Exception e, Object model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, Object model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
//这块是重点代码,我们单独摘抄出来进行讲解
return false;
}
};
- 3、代码逻辑处理,这块是重点
//先判断是否为ImageView类型的Target
if (target instanceof ImageViewTarget) {
final AppCompatImageView imageView = (AppCompatImageView) ((ImageViewTarget) target).getView();
Matrix matrix;
//由于我实在ViewPager中做的图片展示,故先从缓存中取matrix,如果没有在做创建,为了防止对象重复的创建,加大内存的开销
if (imageView.getTag(R.id.common_data_id) == null) {
//这里先获取Drawable原始大小
final int dwidth = resource.getIntrinsicWidth();
final int dheight = resource.getIntrinsicHeight();
//这里获取ImageView的大小,用于后面做比例计算
final int vwidth = imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
final int vheight = imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
float scale;
//这个公式是从ImageView对CENTER_CROP类型的处理的代码段,
if (dwidth * vheight > vwidth * dheight) {
scale = (float) vheight / (float) dheight;
} else {
scale = (float) vwidth / (float) dwidth;
}
matrix = new Matrix();
//设置缩放比例
matrix.setScale(scale, scale);
//将matrix缓存到View中
imageView.setTag(R.id.common_data_id, matrix);
} else {
matrix = (Matrix) imageView.getTag(R.id.common_data_id);
}
//将我们设置好的matrix设置给ImageView
imageView.setImageMatrix(matrix);
}
至此达到scaleType="centerCrop"展示图片,左对齐效果