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,封装这些自定义样式。