Android ImageView-ScaleType源码
来源:互联网 发布:mysql关闭3306端口 编辑:程序博客网 时间:2024/06/05 23:07
首先简单介绍下不同的ScaleType,其实看名字就知道,Scale(比例)Type(类型),这个对象用以调整图片的比例缩放类型。
不同的ScaleType影响的就是图片长与宽的不同缩放比例。matrix 用矩阵来绘制(从左上角起始的矩阵区域)
center 按图片的原来size居中显示,当图片宽超过View的宽,则截取图片的居中部分显示,当图片宽小于View的宽,则图片居中显示
centerCrop 按比例扩大/缩小图片的size居中显示,使得图片的高等于View的高,使得图片宽等于或大于View的宽
centerInside 将图片的内容完整居中显示,使得图片按比例缩小或原来的大小(图片比View小时)使得图片宽等于或小于View的宽 (图片会完整显示)
public void setScaleType(ScaleType scaleType) { if (scaleType == null) { throw new NullPointerException(); } if (mScaleType != scaleType) { mScaleType = scaleType; setWillNotCacheDrawing(mScaleType == ScaleType.CENTER); requestLayout(); invalidate(); } }当设置的 scaleType 和原来 mScaleType = ScaleType.FIT_CENTER 不一样就 则设置缩放类型为scaleType 进行刷新操作 ;
特别的当view的layoutparameter发生改变,并且它的值还没能应用到view上,这时候适合调用这个方法。
/** * When a View's drawing cache is enabled, drawing is redirected to an * offscreen bitmap. Some views, like an ImageView, must be able to * bypass this mechanism if they already draw a single bitmap, to avoid * unnecessary usage of the memory. * * @param willNotCacheDrawing true if this view does not cache its * drawing, false otherwise */ public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); }
当View绘画的时候启用缓存,绘画会重定向到一个
画面以外的位图。例如以一些View,比如一个ImageView,如果他们已经画好一个位图 则可以
忽略这种缓存机制,以避免不必要的内存开销。
/** * Returns whether or not this View can cache its drawing or not. * * @return true if this view does not cache its drawing, false otherwise */ @ViewDebug.ExportedProperty(category = "drawing") public boolean willNotCacheDrawing() { return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; }willNotCacheDrawing()方法放回false 则可以画缓存。
看 ImageView 源码 configureBounds()方法 ,
configureBounds用以处理Matrix和ScaleType的关系
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));
}
}
}
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; }如果drawable 大小未知,或者我们指定了 scaleType.FIT_XY类型 则drawable边界设置为 长宽是 控件长度和宽度。
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; } }如果 图片大小已知 设置Bounds 为图片的实际宽高, if设置的类型是 ScaleType.MARIX,
if (mDrawMatrix != null) { canvas.concat(mDrawMatrix); }
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)); }如果设置的scaleType是 scaleType.FIT_XY 则 mDrawMatrix=null 不要缩放操作
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)); }如果类型是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 ImageView-ScaleType源码
- ImageView.ScaleType / android:scaleType
- 【Android】ImageView.ScaleType说明
- android ImageView scaleType属性
- Android ImageView ScaleType
- android ImageView scaleType属性
- android ImageView scaleType
- android ImageView scaleType属性
- android ImageView scaleType属性
- (Android) ImageView Scaletype
- Android ImageView ScaleType
- android ImageView scaleType属性
- android ImageView scaleType属性
- android ImageView scaleType属性
- android ImageView scaleType属性
- android ImageView scaleType属性
- android ImageView scaleType属性
- android ImageView scaleType属性
- Centos 7 学习之静态IP设置(续)
- android(16)(短信的备份,xml的序列化)
- Network of Schools(强连通分量缩点(邻接表&矩阵))
- 45.KVO(Key-Value-Observer)键值观察者
- Linux命令行移动文件夹到上层目录
- Android ImageView-ScaleType源码
- android app 与电脑wifi通信(二)
- ElasticSearch基本查询
- bzoj1038[ZJOI2008]瞭望塔
- java常见异常分类总结
- vim --整理插件
- voronoi图
- mybatis 调用存储过程(procedure)
- 失物招领发布界面-表单设计