关于ScaleType,网上介绍这个枚举对象的文章很多了,不过基本都只是介绍了它的效果。我在做可缩放移动的ImageView时,为了实现图片的缩放和拖动,需要记录图片的原始Matrix,在使用过程中发现,这个原始Matrix和ScaleType有着直接的关系,不同的ScaleType将会直接影响到Matrix的值进而影响了该自定义控件的效果。为了更好地理清两者的关系,我去阅读了ImageView的源码,在此记录整理后的个人理解。

首先简单介绍下不同的ScaleType,其实看名字就知道,Scale(比例)Type(类型),这个对象用以调整图片的比例缩放类型。不同的ScaleType影响的就是图片长与宽的不同缩放比例。

matrix 用矩阵来绘制(从左上角起始的矩阵区域)
 
fitXY  把图片不按比例扩大/缩小到View的大小显示(确保图片会完整显示,并充满View)
 
fitStart  把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置(图片会完整显示)
 
fitCenter  把图片按比例扩大/缩小到View的宽度,居中显示(图片会完整显示)
 
fitEnd   把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置(图片会完整显示)
center  按图片的原来size居中显示,当图片宽超过View的宽,则截取图片的居中部分显示,当图片宽小于View的宽,则图片居中显示
 
centerCrop  按比例扩大/缩小图片的size居中显示,使得图片的高等于View的高,使得图片宽等于或大于View的宽
 
centerInside  将图片的内容完整居中显示,使得图片按比例缩小或原来的大小(图片比View小时)使得图片宽等于或小于View的宽 (图片会完整显示)
 
我们知道,可以使用getImageMatrix方法获取ImageView中图片的Matrix对象,事实上,ScaleType影响的也正是该Matrix对象。在ImageView源码中,configureBounds用以处理Matrix和ScaleType的关系。接下去通过阅读源码来解释下为什么会实现上述显示效果。
 
configureBounds源码如下:
private void configureBounds() {
if (mDrawable == null || !mHaveFrame) {
return;
} int dwidth = mDrawableWidth;
int dheight = mDrawableHeight; int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
int vheight = getHeight() - mPaddingTop - mPaddingBottom; boolean fits = (dwidth < 0 || vwidth == dwidth) &&
(dheight < 0 || vheight == dheight); if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
/* If the drawable has no intrinsic size, or we're told to
scaletofit, then we just fill our entire view.
*/
mDrawable.setBounds(0, 0, vwidth, vheight);
mDrawMatrix = null;
} else {
// We need to do the scaling ourself, so have the drawable
// use its native size.
mDrawable.setBounds(0, 0, dwidth, dheight); if (ScaleType.MATRIX == mScaleType) {
// Use the specified matrix as-is.
if (mMatrix.isIdentity()) {
mDrawMatrix = null;
} else {
mDrawMatrix = mMatrix;
}
} else if (fits) {
// The bitmap fits exactly, no transform needed.
mDrawMatrix = null;
} else if (ScaleType.CENTER == mScaleType) {
// Center bitmap in view, no scaling.
mDrawMatrix = mMatrix;
mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),
(int) ((vheight - dheight) * 0.5f + 0.5f));
} else 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((int) (dx + 0.5f), (int) (dy + 0.5f));
} else if (ScaleType.CENTER_INSIDE == mScaleType) {
mDrawMatrix = mMatrix;
float scale;
float dx;
float dy; if (dwidth <= vwidth && dheight <= vheight) {
scale = 1.0f;
} else {
scale = Math.min((float) vwidth / (float) dwidth,
(float) vheight / (float) dheight);
} dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f); mDrawMatrix.setScale(scale, scale);
mDrawMatrix.postTranslate(dx, dy);
} else {
// Generate the required transform.
mTempSrc.set(0, 0, dwidth, dheight);
mTempDst.set(0, 0, vwidth, vheight); mDrawMatrix = mMatrix;
mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
}
}
}

分段阅读:

int dwidth = mDrawableWidth;
int dheight = mDrawableHeight; int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
int vheight = getHeight() - mPaddingTop - mPaddingBottom; boolean fits = (dwidth < 0 || vwidth == dwidth) &&
(dheight < 0 || vheight == dheight);

1.在这一步中,获取了图片对象(即Drawable对象,ImageView实际显示的是Drawable对象)的宽度和高度,存放在dwidth和dheight中。同时,获取了ImageView控件的显示区域的宽度和高度,存放在vwidth和vheight中。

if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
/* If the drawable has no intrinsic size, or we're told to
scaletofit, then we just fill our entire view.
*/
mDrawable.setBounds(0, 0, vwidth, vheight);
mDrawMatrix = null;
} else {

2.当图片的大小未知或者ScaleType为FIT_XY时,将drawable的边界设置为控件的大小,并且将图片matrix对象设置为null。setBounds方法用以设置Drawable绘制区域的大小,是一个矩形对象。在ImageView的onDraw方法中,最终会将Drawable表示的图片绘制到该区域上。在这里,就是将图片绘制到ImageView大小的区域上,也就是所谓的图片完整显示,填充满ImageView。注意此处并未对Matrix对象进行操作,而是直接设置为null,所以当ImageView的ScaleType为FIT_XY时,getImageMatrix将获取到一个初始Matrix对象,getImageMatrix方法如下。

 public Matrix getImageMatrix() {
if (mDrawMatrix == null) {
return new Matrix(Matrix.IDENTITY_MATRIX);
}
return mDrawMatrix;
}
else {
// We need to do the scaling ourself, so have the drawable
// use its native size.
mDrawable.setBounds(0, 0, dwidth, dheight);

3.当ScaleType不为FIT_XY并且图片宽高不为0,就会把drawable的绘制区域设成图片实际大小。注:此处的实际大小不是指文件大小,而是指源文件大小和屏幕分辨率计算后的结果。

 if (ScaleType.MATRIX == mScaleType) {
// Use the specified matrix as-is.
if (mMatrix.isIdentity()) {
mDrawMatrix = null;
} else {
mDrawMatrix = mMatrix;
}
} else if (fits) {
// The bitmap fits exactly, no transform needed.
mDrawMatrix = null;
}

4.接下去判断ScaleType是否为MATRIX,如果为MATRIX类型,就会把当前绘制用的的Matrix赋值为mMatrix,mMatrix是通过setImageMatrix方法赋值的。这之后还有一个if(fits)判断,假如fits为true,表示图片大小等于ImageView大小,也不需要进行缩放操作了。

else if (ScaleType.CENTER == mScaleType) {
// Center bitmap in view, no scaling.
mDrawMatrix = mMatrix;
mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),
(int) ((vheight - dheight) * 0.5f + 0.5f));
}

5.当ScaleType类型为CENTER时,实际操作是将图片进行右移和下移操作,移动的数值分别为为ImageView宽度、高度与图片宽度、高度差值的一半,这样就达到了居中显示的效果。注意,CENTER不进行缩放操作只进行位移操作,所以图片的显示大小并未改变,当图片大于控件时,只显示居中部分,大于控件的部分未显示。

else 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((int) (dx + 0.5f), (int) (dy + 0.5f));
}

6.在CENTER_CROP中,首先对dwidth * vheight > vwidth * dheight进行了一个判断,这个判断是什么意思呢?其实换成这样比较容易理解:dwidth/vwidth>dheight/vheight,即判断到底是图片的宽度比较接近控件宽度还是图片高度比较控件高度,最终会取相差较大的项,将其放大至控件对应的值。而另外一项将超出控件大小。之后,对其进行位移,使超出控件大小的一项居中显示。注:当图片大于控件时,是将超出更少的项进行缩放。CROP的目的在于对图片宽高进行变换,使其中一项和控件的值相等,另外一项大于控件的值。

else if (ScaleType.CENTER_INSIDE == mScaleType) {
mDrawMatrix = mMatrix;
float scale;
float dx;
float dy; if (dwidth <= vwidth && dheight <= vheight) {
scale = 1.0f;
} else {
scale = Math.min((float) vwidth / (float) dwidth,
(float) vheight / (float) dheight);
} dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f); mDrawMatrix.setScale(scale, scale);
mDrawMatrix.postTranslate(dx, dy);
}

7.当为CENTER_INSIDE时,若图片高宽均小于控件高宽,则不进行缩放只进行偏移,偏移方式跟其他情况相同。否则,将根据图片和控件的宽高比例差距更大的一项进行缩放,缩放的结果就是其中一项和控件相同,另外一项小于控件值。这个刚好和CENTER_CROP相反。

else {
// Generate the required transform.
mTempSrc.set(0, 0, dwidth, dheight);
mTempDst.set(0, 0, vwidth, vheight); mDrawMatrix = mMatrix;
mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
}

8.最后三种FIT_CENTER、FIT_START、FIT_END都是调用setRectToRect获取缩放偏移矩阵。setRectTorect返回一个Matrix,该Matrix表示从矩形mTempSrc到mTemDst的变换矩阵,根据第三个参数Matrix.ScaleToFit来确定缩放选项。

Matrix.ScaleToFit定义了四种选项:

CENTER: 保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。
END:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。END提供右下对齐。
FILL: 可能会变换矩形的长宽比,保证变换和目标矩阵长宽一致。
START:保持坐标变换前矩形的长宽比,并最大限度的填充变换后的矩形。至少有一边和目标矩形重叠。START提供左上对齐。

ScaleType的FIT_CENTER、FIT_START、FIT_END分别对应于这里的CENTER、END、START。

总结下就一句话:ScaleType本质上是影响了ImageView中的mDrawMatrix对象,该对象用以在绘制时对Drawable对象进行矩阵转换。

Android:ScaleType与Matrix相关的更多相关文章

  1. android:scaleType=&quot;matrix&quot;布局文件载入图片时候的显示方式

    android:scaleType="center" 以原图的几何中心点和ImagView的几何中心点为基准,按图片的原来size居中显示,不缩放,当图片长/宽超过View的长/宽 ...

  2. android ImageView的属性android:scaleType,即ImageView.setScaleType(ImageView.ScaleType)

    实例 <ImageView android:id="@+id/image" android:layout_width="fill_parent" andr ...

  3. ImageView的属性android:scaleType,即ImageView.setScaleType(ImageView.ScaleType)

    1 imageView.setScaleType(ImageView.ScaleType.FIT_XY ); 1 这里我们重点理解ImageView的属性android:scaleType,即Imag ...

  4. Android ImageView的属性android:scaleType

    ImageView的属性android:scaleType,即ImageView.setScaleType(ImageView.ScaleType) imageView.setScaleType(Im ...

  5. 图片的ScaleType详解 ImageView的属性android:scaleType,

    imageView.setScaleType(ImageView.ScaleType.FIT_XY ); 这里我们重点理解ImageView的属性android:scaleType,即ImageVie ...

  6. 转载《android:scaleType属性》

    在网上查了好多资料,大致都雷同,大家都是互相抄袭的,看着很费劲,不好理解,自己总结一下,留着需要看的话来查找. 代码中的例子如下: <ImageView android:id="@+i ...

  7. Android中图像变换Matrix的原理、代码验证和应用(一)

    第一部分 Matrix的数学原理 在Android中,如果你用Matrix进行过图像处理,那么一定知道Matrix这个类.Android中的Matrix是一个3 x 3的矩阵,其内容如下: Matri ...

  8. android:scaleType属性

    Android:scaleType是控制图片如何resized/moved来匹对ImageView的size. ImageView.ScaleType / android:scaleType值的意义区 ...

  9. Android ImageButton android:scaleType

    ImageView的属性android:scaleType,即 ImageView.setScaleType(ImageView.ScaleType). android:scaleType是控制图片如 ...

随机推荐

  1. 微信小程序的一些数据调用方式

    1.模板数据的调用 一张图了解一下在wxml页调用预先定义好的模板: 可以看到上面调用了两个模板,数据调用却是不同的,obj是一个对象,对象内包含多个键值对形式的数据: tabbar是一个一维数组,每 ...

  2. Shell 循环中实现展示进度百分比的脚本方法

    Shell 循环中实现展示进度百分比的脚本方法 当我需要处理一个几万行的文件的时候,需要处理的时间是比较长的.我一开始的想法是,没处理一行,就输出一个 # 号.但是这样还是会出现很多很多的 # 号,即 ...

  3. Android程序员学WEB前端(4)-HTML(4)-注册页面-Sublime

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/76576031 觉得博文有用,请点赞,请评论,请关注,谢谢!~ 注册页面1: <! ...

  4. HDU 1452

    http://acm.hdu.edu.cn/showproblem.php?pid=1452 原来真心没见过这种题,不会做,非常帅 gcd(a,b)==1 && s(a,b)==s(a ...

  5. BZOJ - 3223 Tyvj 1729 文艺平衡树 (splay/无旋treap)

    题目链接 splay: #include<bits/stdc++.h> using namespace std; typedef long long ll; ,inf=0x3f3f3f3f ...

  6. 每天一个linux命令(性能、优化):【转载】free命令

    free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存,及被内核使用的buffer.在Linux系统监控的工具中,free命令是最经常使用的命令之一. 1.命令格式: free [参 ...

  7. 为什么 UEFI 方式启动的 U 盘必须使用 FAT32 文件系统?

    如果你希望更刺激地安装 Windows,那么你需要了解很多 Windows 系统相关的问题. 为什么 UEFI 方式启动的 U 盘必须使用 FAT32 文件系统? 因为 NTFS 是 Windows ...

  8. WebLogic11g-创建域(Domain)及基本配置

    转:http://www.codeweblog.com/weblogic11g-%e5%88%9b%e5%bb%ba%e5%9f%9f-domain-%e5%8f%8a%e5%9f%ba%e6%9c% ...

  9. flask第七篇——URL与视图函数的映射

    有兴趣的朋友可以添加微信公众号:自动化测试实战 今天开始就要进入正题了.大家都准备好了吧~ 代码提示 先和大家说个小知识点:有同学后台说输入flask代码pycharm不提示,现在告诉你一个解决方法: ...

  10. 【java基础】java集合之TreeMap

    转载文章转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3310928 第1部分 TreeMap介绍 T ...