实现圆角矩形的ImageView最简单的方式可以使用裁剪 和CardView 来实现,但是裁剪的API只支持在Android 5.0及其以上的设备,所以适配起来可能会有问题,为了省去适配的麻烦,我们可以使用自定义控件的方式来实现圆角矩形的ImageView。
通过Xfermode方式实现 使用画笔Paint去绘制东西,当绘制多个图层叠加的时候,有16种模式。效果如下图。
模式
说明
PorterDuff.Mode.CLEAR
所有绘制不会绘制到画布上
PorterDuff.Mode.SRC
显示上层绘制图形
PorterDuff.Mode.DST
显示下层绘制图形
PorterDuff.Mode.SRC_OVER
图形叠加,上层盖住下层
PorterDuff.Mode.DST_OVER
图形叠加,下层盖住上层
PorterDuff.Mode.SRC_IN
显示上层交集部分
PorterDuff.Mode.DST_IN
显示下层交集部分
PorterDuff.Mode.SRC_OUT
显示上层非交集部分
PorterDuff.Mode.DST_OUT
显示下层非交集部分
PorterDuff.Mode.SRC_ATOP
显示下层非交集部分和上层交集部分
PorterDuff.Mode.DST_ATOP
显示下层交集部分与上层非交集部分
PorterDuff.Mode.XOR
去除交集部分
PorterDuff.Mode.DARKEN
交集部分颜色加深
PorterDuff.Mode.LIGHTEN
交集部分颜色变亮
PorterDuff.Mode.MULTIPLY
显示交集部分,颜色混合叠加
PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色
官方demo中主要绘制代码如下:
1 2 3 4 5 // mDstB是黄色的圆形图bitmap // mSrcB是蓝色的矩形图bitmap canvas.drawBitmap(mDstB, 0, 0, paint); paint.setXfermode(sModes[i]); canvas.drawBitmap(mSrcB, 0, 0, paint)
可以看到在两个绘制图形过程中,添加Xfermode绘制模式,能够改变两个图的叠加效果,我们主要关注一下SrcIn模式,可以看见,用图层叠加的交集去截取mSrcB图,可以利用这个,想绘制一个圆角的图,然后设置绘制模式,接着绘制一个矩形的图,两者一叠加,正好是用圆角图去截取矩形图,矩形图也就是我们的原图片了。
代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 public class RoundRectImageViewA extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewA(Context context) { super(context); } public RoundRectImageViewA(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewA(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); //处理Bitmap 转成正方形 Bitmap newBitmap = scaleBitmap(rawBitmap); //将newBitmap 转换成圆形 Bitmap circleBitmap = toRoundCorner(newBitmap, 30); final Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rect, rect, paint); } else { super.onDraw(canvas); } } //将头像按比例缩放 private Bitmap scaleBitmap(Bitmap bitmap){ int width = getWidth(); int height = getHeight(); //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误 float scaleX = (float)width/(float)bitmap.getWidth(); float scaleY = (float) height / (float) bitmap.getHeight(); Matrix matrix = new Matrix(); matrix.postScale(scaleX, scaleY); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } private Bitmap toRoundCorner(Bitmap bitmap, int radius) { //指定为 ARGB_4444 可以减小图片大小 Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Rect rect = new Rect(0, 0,bitmap.getWidth(), bitmap.getHeight()); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); int x = bitmap.getWidth(); canvas.drawRoundRect(new RectF(0,0,bitmap.getWidth(),bitmap.getHeight()), radius,radius, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } }
大多数情况下,要展示图片的控件(ImageView)的长宽和图片的长宽并不是一致的,甚至长宽比都不一致,所以在拿到一张图片时候,大多数情况下需要根据控件的大小对图片进行拉伸缩放处理,有人会问为什么不直接使用ImageView属性scaleType去控制拉伸缩放,这是因为当我们将一个Bitmap绘制成圆角后,再去进行拉伸缩放,圆角可能会变形,所以在Bitmap设置到控件之前就需要对Bitmap进行一下拉伸缩放处理,直接看下面代码。
1 2 3 4 5 6 7 8 // 图片根据控件大小等比例缩放拉伸 float widthScale = imageViewWidth * 1.0f / bitmap.getWidth(); float heightScale = imageViewHeight * 1.0f / bitmap.getHeight(); // 设置长宽拉伸缩放比 Matrix matrix = new Matrix(); matrix.setScale(widthScale, heightScale); // 拉伸缩放图片 Bitmap newBt = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
拉伸缩放也可以在
1 Canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
方法中控制。
利用这种缩放方式实现了RoundRectImageViewB(有问题,还未找到原因),代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 public class RoundRectImageViewB extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewB(Context context) { super(context); } public RoundRectImageViewB(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewB(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); //将newBitmap 转换成圆形 Bitmap circleBitmap = toRoundCorner(rawBitmap, 30); final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); final Rect rectDes = new Rect(0, 0, getWidth(), getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint); } else { super.onDraw(canvas); } } //将原始图像裁剪成正方形 private Bitmap dealRawBitmap(Bitmap bitmap){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); //获取宽度 int minWidth = width > height ? height:width ; //计算正方形的范围 int leftTopX = (width - minWidth)/2; int leftTopY = (height - minWidth)/2; //裁剪成正方形 Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false); return newBitmap; } //将头像按比例缩放 private Bitmap scaleBitmap(Bitmap bitmap){ int width = getWidth(); //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误 float scale = (float)width/(float)bitmap.getWidth(); Matrix matrix = new Matrix(); matrix.postScale(scale, scale); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } private Bitmap toRoundCorner(Bitmap bitmap, int radius) { //指定为 ARGB_4444 可以减小图片大小 Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Rect rect = new Rect(0, 0,bitmap.getWidth(), bitmap.getHeight()); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); int x = bitmap.getWidth(); canvas.drawRoundRect(new RectF(0,0,bitmap.getWidth(),bitmap.getHeight()), radius,radius, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } }
通过BitmapShader方式实现 所有的绘制圆角的实现,推荐使用这个方法,不仅仅可以帮助我们实现圆角,连部分圆角都可以实现,比如顶部是两个圆角,底部是两个直角的图片。
首先介绍一下BitmapShader 这个类,它作为纹理用于绘制一张图。新图可以是纹理图重复/镜像/边缘像素拉伸而绘制成的新图。这个类构造函数很简单,BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) ,第一个参数是Bitmap,作为纹理图传入,tileX是指在水平方向上的绘制方式,tileY是指在竖直方向上的绘制方式。TileMode 有三种属性,拉伸、重复、镜像。
TileMode.CLAMP 拉伸绘制,并不是指图片拉伸,而是指图片最后一个像素不断绘制,纹理图水平或者竖直方向最后一个像素不断绘制
TileMode.REPEAT 重复绘制,在水平或者竖直方向上不断重复绘制纹理图
TileMode.MIRROR 镜像绘制,水平或者竖直方向不断的绘制翻转纹理图
使用BitmapShader绘制图的时候,是从画布的左上角开始绘制的。我们是使用拉伸的绘制模式,直接来看一下代码,了解处理过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public class RoundRectImageViewC extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewC(Context context) { super(context); } public RoundRectImageViewC(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewC(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); Bitmap newBitmap = scaleBitmap(rawBitmap); Bitmap circleBitmap = toRoundCorner(newBitmap, 30); final Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rect, rect, paint); } else { super.onDraw(canvas); } } //将头像按比例缩放 private Bitmap scaleBitmap(Bitmap bitmap){ int width = getWidth(); int height = getHeight(); //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误 float scaleX = (float)width/(float)bitmap.getWidth(); float scaleY = (float) height / (float) bitmap.getHeight(); Matrix matrix = new Matrix(); matrix.postScale(scaleX, scaleY); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } private Bitmap toRoundCorner(Bitmap bitmap, int radius) { // 初始化绘制纹理图 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //指定为 ARGB_4444 可以减小图片大小 Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(output); // 初始化画笔 Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(bitmapShader); // 利用画笔将纹理图绘制到画布上面 canvas.drawRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, paint); return output; } }
首先初始化了绘制的纹理图。然后初始化了画布和画笔,设置画笔绘制的纹理图,画笔在绘制图形时候就不是使用单纯的颜色绘制了。最后在利用画笔在画布上面绘制出圆形图片。
利用Rect实现缩放的RoundImageViewD(有问题,还未找到原因)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public class RoundRectImageViewD extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewD(Context context) { super(context); } public RoundRectImageViewD(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewD(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); Bitmap circleBitmap = toRoundCorner(rawBitmap, 30); final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); final Rect rectDes = new Rect(0, 0, getWidth(), getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint); } else { super.onDraw(canvas); } } private Bitmap toRoundCorner(Bitmap bitmap, int radius) { // 初始化绘制纹理图 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //指定为 ARGB_4444 可以减小图片大小 Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(output); // 初始化画笔 Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(bitmapShader); // 利用画笔将纹理图绘制到画布上面 canvas.drawRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, paint); return output; } }
利用BitmapShader还可以实现很多其他样式的效果,有下面几种:
底部两个圆角,顶部两个直角,
四角都是圆角
同边圆角,底部圆角/顶部圆角/左边圆角/右边圆角
对角线圆角,左上右下圆角/左下右上圆角
单个圆角,左上圆角/左下圆角/右上圆角/右下圆角
三个圆角,左上非圆角/左下非圆角/右上非圆角/右下非圆角
具体请参考:Android圆角图片和圆形图片实现总结 。
通过画布裁剪的方式实现 关于画布裁剪的知识,建议阅读:Canvas的裁剪 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 public class RoundRectImageViewE extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewE(Context context) { super(context); } public RoundRectImageViewE(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewE(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); //处理Bitmap 转成正方形 Bitmap newBitmap = dealRawBitmap(rawBitmap); //将newBitmap 转换成圆形 Bitmap circleBitmap = toRoundCorner(newBitmap,30); final Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rect, rect, paint); } else { super.onDraw(canvas); } } //将原始图像裁剪成正方形 private Bitmap dealRawBitmap(Bitmap bitmap){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); //获取宽度 int minWidth = width > height ? height:width ; //计算正方形的范围 int leftTopX = (width - minWidth)/2; int leftTopY = (height - minWidth)/2; //裁剪成正方形 Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false); return scaleBitmap(newBitmap); } //将头像按比例缩放 private Bitmap scaleBitmap(Bitmap bitmap){ int width = getWidth(); int height = getHeight(); //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误 float scaleX = (float)width/(float)bitmap.getWidth(); float scaleY = (float) height / (float) bitmap.getHeight(); Matrix matrix = new Matrix(); matrix.postScale(scaleX, scaleY); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } private Bitmap toRoundCorner(Bitmap bitmap,int radius) { //指定为 ARGB_4444 可以减小图片大小 Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(output); // 初始化画笔 Paint paint = new Paint(); paint.setAntiAlias(true); paint.setFilterBitmap(true); Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); Path path = new Path(); path.addRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, Path.Direction.CW); canvas.clipPath(path, Region.Op.INTERSECT); canvas.drawBitmap(bitmap,rect,rect,paint); return output; } }
通过Rect缩放实现的RoundRectImageViewF。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 /** * 圆形控件 * * @author zhangyan * */ public class RoundRectImageViewF extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewF(Context context) { super(context); } public RoundRectImageViewF(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewF(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); //处理Bitmap 转成正方形 Bitmap newBitmap = dealRawBitmap(rawBitmap); //将newBitmap 转换成圆形 Bitmap circleBitmap = toRoundCorner(newBitmap,30); final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); final Rect rectDes = new Rect(0, 0, getWidth(), getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint); } else { super.onDraw(canvas); } } //将原始图像裁剪成正方形 private Bitmap dealRawBitmap(Bitmap bitmap){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); //获取宽度 int minWidth = width > height ? height:width ; //计算正方形的范围 int leftTopX = (width - minWidth)/2; int leftTopY = (height - minWidth)/2; //裁剪成正方形 Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false); return newBitmap; } private Bitmap toRoundCorner(Bitmap bitmap,int radius) { //指定为 ARGB_4444 可以减小图片大小 Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(output); // 初始化画笔 Paint paint = new Paint(); paint.setAntiAlias(true); paint.setFilterBitmap(true); Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); Path path = new Path(); path.addRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, Path.Direction.CW); canvas.clipPath(path, Region.Op.INTERSECT); canvas.drawBitmap(bitmap,rect,rect,paint); return output; } }
在面试的过程中阿里的面试官说这种方案会新建一个Bitmap,所以可能会导致内存占用率过高。我们可以改进上面的裁剪的实现方式,直接在原来的画布上进行裁剪,避免创建新的的Bitmap,改进后的代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 /** * 圆形控件 * * @author zhangyan * */ public class RoundRectImageViewE extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewE(Context context) { super(context); } public RoundRectImageViewE(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewE(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); //处理Bitmap 转成正方形 Bitmap circleBitmap = dealRawBitmap(rawBitmap); Path path = new Path(); path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), 30, 30, Path.Direction.CW); canvas.clipPath(path, Region.Op.INTERSECT); Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rect, rect, paint); } else { super.onDraw(canvas); } } //将原始图像裁剪成正方形 private Bitmap dealRawBitmap(Bitmap bitmap){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); //获取宽度 int minWidth = width > height ? height:width ; //计算正方形的范围 int leftTopX = (width - minWidth)/2; int leftTopY = (height - minWidth)/2; //裁剪成正方形 Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false); return scaleBitmap(newBitmap); } //将头像按比例缩放 private Bitmap scaleBitmap(Bitmap bitmap){ int width = getWidth(); int height = getHeight(); //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误 float scaleX = (float)width/(float)bitmap.getWidth(); float scaleY = (float) height / (float) bitmap.getHeight(); Matrix matrix = new Matrix(); matrix.postScale(scaleX, scaleY); return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } }
(实现的圆角矩形没有任何问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class RoundRectImageViewF extends ImageView { private Paint paint = new Paint(); public RoundRectImageViewF(Context context) { super(context); } public RoundRectImageViewF(Context context, AttributeSet attrs) { super(context, attrs); } public RoundRectImageViewF(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { Drawable drawable = getDrawable(); if (null != drawable) { Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap(); //处理Bitmap 转成正方形 Bitmap circleBitmap = dealRawBitmap(rawBitmap); Path path = new Path(); path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), 30, 30, Path.Direction.CW); canvas.clipPath(path, Region.Op.INTERSECT); final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight()); final Rect rectDes = new Rect(0, 0, getWidth(), getHeight()); paint.reset(); //绘制到画布上 canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint); } else { super.onDraw(canvas); } } //将原始图像裁剪成正方形 private Bitmap dealRawBitmap(Bitmap bitmap){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); //获取宽度 int minWidth = width > height ? height:width ; //计算正方形的范围 int leftTopX = (width - minWidth)/2; int leftTopY = (height - minWidth)/2; //裁剪成正方形 Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false); return newBitmap; } }
Demo链接:ImageViews
参考链接:
Android自定义圆角矩形ImageView,支持Glide加载图片及颜色填充 (XferMode方式主要参考自这篇文章)
【Android】自定义圆形ImageView(圆形头像 可指定大小)
Android自定义圆角矩形ImageView,支持Glide加载图片及颜色填充 &&Android圆角图片和圆形图片实现总结 (利用Rect对Bitmap进行缩放,参考自这两篇文章)
Android圆角图片和圆形图片实现总结 (BitmapShader方式主要参考自这篇文章,这篇文章也详细的介绍了Xfermode的相关知识)
各个击破搞明白PorterDuff.Mode (推荐阅读这个)
Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解
细数PorterDuffXferMode的几个坑, PorterDuffXferMode不正确的真正原因
android canvas void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)
Bitmap createBitmap参数(三)
上一篇:图片的圆形效果
下一篇:自定义圆形的ImageView