本文已授权我的公众号:我就是马云飞 独家发布
不知道有没有人记得我去年写过一个圆角的imageview。不知道的可以先去看看:万能圆角imagview,本文是基于上一篇的内容进行添加以及修改的。不然直接看这篇可能会有点懵。
同事说,不知道怎么搞,于是乎,我把之前写的imageview给过去了。他来了句,你这圆角和fitxy同时设置会有问题啊,我反手就是一个大嘴巴子。我的代码怎么会有问题。于是,拿来一瞧,的确有点问题。So,我决定对这个imageview进行二次的封装。(当然了,这个问题的最后处理是后台直接给一个圆角的imageview)。
细想一下,上文我们是怎么做的,我们是把绘制的区域,从(0,0)移动到我们想要的地方,说个粗暴点的话,我们强制的把这个imagview的scaletype的属性设置了centercrop。那么这次我们就要将它的scaletype设置成可调的属性。
我前面也说过了,上次我们是根据imageview的源码来修改他的编辑区域的,这次,我们照常打开源码,找到园中对scaletype的处理逻辑,代码如下:
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 (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(Math.round((vwidth - dwidth) * 0.5f),
Math.round((vheight - dheight) * 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(Math.round(dx), Math.round(dy));
} 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 = Math.round((vwidth - dwidth * scale) * 0.5f);
dy = Math.round((vheight - dheight * scale) * 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 (drawablewidth <= 0 || drawableheight <= 0) {
drawable.setBounds(0, 0, viewwidth, viewheight);
matrix = null;
} else {
drawable.setBounds(0, 0, drawablewidth, drawableheight);
if (ScaleType.MATRIX == getScaleType()) {
if (matrix.isIdentity()) {
matrix = null;
}
} else if (fits) {
matrix = null;
} else if (ScaleType.CENTER == getScaleType()) {
matrix.setTranslate(Math.round((viewwidth - drawablewidth) * 0.5f),
Math.round((viewheight - drawableheight) * 0.5f));
} else if (ScaleType.CENTER_CROP == getScaleType()) {
if (drawablewidth * viewheight > viewwidth * drawableheight) {
dx = (viewwidth - drawablewidth * scale) * 0.5f;
} else {
dy = (viewheight - drawableheight * scale) * 0.5f;
}
matrix.setScale(scale, scale);
matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
} else if (ScaleType.CENTER_INSIDE == getScaleType()) {
if (drawablewidth <= viewwidth && drawableheight <= viewheight) {
scale = 1.0f;
} else {
scale = Math.min((float) viewwidth / (float) drawablewidth,
(float) viewheight / (float) drawableheight);
}
dx = Math.round((viewwidth - drawablewidth * scale) * 0.5f);
dy = Math.round((viewheight - drawableheight * scale) * 0.5f);
matrix.setScale(scale, scale);
matrix.postTranslate(dx, dy);
} else {
if (drawablewidth * viewheight > viewwidth * drawableheight) {
dx = (viewwidth - drawablewidth * scale) * 0.5f;
} else {
dy = (viewheight - drawableheight * scale) * 0.5f;
}
matrix.setScale(scale, scale);
matrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
}
}
if (ScaleType.FIT_XY == getScaleType() && matrix != null) {
scale1 = viewwidth * 1.0f / drawablewidth;
scale2 = viewheight * 1.0f / drawableheight;
matrix.setScale(scale1, scale2);
}
bitmapShader.setLocalMatrix(matrix);
paint.setShader(bitmapShader);
我们可以发现其实和源码对比下来,改动还是有的。为什么呢?我们仔细看下这段代码:
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进行了处理。但我们可以发现后面的判断每次都会调用matrix.setScale这个方法。但在当scaletype为fitxy时,没有进行处理。我们也知道,我们看的是源码,他肯定偷偷的在某个地方进行了处理。那么我们要处理怎么办呢?仔细看代码:
if (ScaleType.FIT_XY == getScaleType() && matrix != null) {
scale1 = viewwidth * 1.0f / drawablewidth;
scale2 = viewheight * 1.0f / drawableheight;
matrix.setScale(scale1, scale2);
}
fitxy我们都知道是充满布局,然后在细看这块代码,你是不是懂了呢?布局的宽高除以图片的宽高。然后设置它的比例。
为了更好的封装,我选择加上边框和边框颜色的自定义属性。那么接下来就是直接上代码了。
我们需要再定义一个画笔:
boder_paint.setAntiAlias(true);
boder_paint.setStyle(Paint.Style.STROKE);
boder_paint.setColor(border_color);
boder_paint.setStrokeWidth(border_width);
接下来我们就是直接画上去了。当然了,我们这边默认是不设置,也就是borderwidth为0,所以我们要加一个判断:
if (type == TYPE_ROUND) {
canvas.drawRoundRect(rectF, borderRadius, borderRadius,paint);
if (border_width > 0) {
canvas.drawRoundRect(rectF, borderRadius, borderRadius, boder_paint);
}
} else if (type == TYPE_CIRCLE) {
canvas.drawCircle(radius, radius, radius, paint);
if (border_width > 0) {
canvas.drawCircle(radius, radius, radius, boder_paint);
}
} else {
getDrawable().draw(canvas);
}
我们一编译,一运行,效果炸了。你问我为什么?我们先来看个效果在说把。
我们发现我们修改的fitxy属性已经生效了。但是,为什么加了边框是这样呢?
仔细想想。我们画圆角和圆的时候是不是忘记去掉了边框的宽度呢?那么我们既然找到了原因就可以找到解决方法了。那我们就直接去掉边框的高度,注意!!圆角和圆的都要处理。
canvas.drawCircle(radius, radius, radius, paint);
if (border_width > 0) {
canvas.drawCircle(radius, radius, radius - border_width / 2, boder_paint);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (type == TYPE_ROUND) {
rectF = new RectF(border_width/2,border_width/2, getWidth()- border_width / 2, getHeight()- border_width / 2);
}
}
在gradle加上如下代码:
compile 'com.angel:SWImageView:1.0.0'
关于自定义属性:
<declare-styleable name="SWImageView">
<attr name="borderRadius" format="dimension"/>
<attr name="type">
<enum name="normal" value="-1"/>
<enum name="circle" value="0"/>
<enum name="round" value="1"/>
attr>
<attr name="borderWidth" format="dimension" />
<attr name="borderColor" format="integer" />
declare-styleable>
我觉得命名很清晰明了。我就不介绍了。
项目我已上传到github:https://github.com/sw950729/SWImageView 喜欢的朋友随手点了star。谢谢。