[关闭]
@946898963 2019-10-04T16:38:21.000000Z 字数 16439 阅读 2537

自定义圆角矩形的ImageView

Android自定义控件 Android绘图


实现圆角矩形的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. // mDstB是黄色的圆形图bitmap
  2. // mSrcB是蓝色的矩形图bitmap
  3. canvas.drawBitmap(mDstB, 0, 0, paint);
  4. paint.setXfermode(sModes[i]);
  5. canvas.drawBitmap(mSrcB, 0, 0, paint)

可以看到在两个绘制图形过程中,添加Xfermode绘制模式,能够改变两个图的叠加效果,我们主要关注一下SrcIn模式,可以看见,用图层叠加的交集去截取mSrcB图,可以利用这个,想绘制一个圆角的图,然后设置绘制模式,接着绘制一个矩形的图,两者一叠加,正好是用圆角图去截取矩形图,矩形图也就是我们的原图片了。

代码如下所示:

  1. public class RoundRectImageViewA extends ImageView {
  2. private Paint paint = new Paint();
  3. public RoundRectImageViewA(Context context) {
  4. super(context);
  5. }
  6. public RoundRectImageViewA(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. public RoundRectImageViewA(Context context, AttributeSet attrs, int defStyle) {
  10. super(context, attrs, defStyle);
  11. }
  12. @Override
  13. protected void onDraw(Canvas canvas) {
  14. Drawable drawable = getDrawable();
  15. if (null != drawable) {
  16. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  17. //处理Bitmap 转成正方形
  18. Bitmap newBitmap = scaleBitmap(rawBitmap);
  19. //将newBitmap 转换成圆形
  20. Bitmap circleBitmap = toRoundCorner(newBitmap, 30);
  21. final Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  22. paint.reset();
  23. //绘制到画布上
  24. canvas.drawBitmap(circleBitmap, rect, rect, paint);
  25. } else {
  26. super.onDraw(canvas);
  27. }
  28. }
  29. //将头像按比例缩放
  30. private Bitmap scaleBitmap(Bitmap bitmap){
  31. int width = getWidth();
  32. int height = getHeight();
  33. //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误
  34. float scaleX = (float)width/(float)bitmap.getWidth();
  35. float scaleY = (float) height / (float) bitmap.getHeight();
  36. Matrix matrix = new Matrix();
  37. matrix.postScale(scaleX, scaleY);
  38. return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  39. }
  40. private Bitmap toRoundCorner(Bitmap bitmap, int radius) {
  41. //指定为 ARGB_4444 可以减小图片大小
  42. Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
  43. Canvas canvas = new Canvas(output);
  44. final int color = 0xff424242;
  45. final Rect rect = new Rect(0, 0,bitmap.getWidth(), bitmap.getHeight());
  46. paint.setAntiAlias(true);
  47. canvas.drawARGB(0, 0, 0, 0);
  48. paint.setColor(color);
  49. int x = bitmap.getWidth();
  50. canvas.drawRoundRect(new RectF(0,0,bitmap.getWidth(),bitmap.getHeight()), radius,radius, paint);
  51. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
  52. canvas.drawBitmap(bitmap, rect, rect, paint);
  53. return output;
  54. }
  55. }

大多数情况下,要展示图片的控件(ImageView)的长宽和图片的长宽并不是一致的,甚至长宽比都不一致,所以在拿到一张图片时候,大多数情况下需要根据控件的大小对图片进行拉伸缩放处理,有人会问为什么不直接使用ImageView属性scaleType去控制拉伸缩放,这是因为当我们将一个Bitmap绘制成圆角后,再去进行拉伸缩放,圆角可能会变形,所以在Bitmap设置到控件之前就需要对Bitmap进行一下拉伸缩放处理,直接看下面代码。

  1. // 图片根据控件大小等比例缩放拉伸
  2. float widthScale = imageViewWidth * 1.0f / bitmap.getWidth();
  3. float heightScale = imageViewHeight * 1.0f / bitmap.getHeight();
  4. // 设置长宽拉伸缩放比
  5. Matrix matrix = new Matrix();
  6. matrix.setScale(widthScale, heightScale);
  7. // 拉伸缩放图片
  8. 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. public class RoundRectImageViewB extends ImageView {
  2. private Paint paint = new Paint();
  3. public RoundRectImageViewB(Context context) {
  4. super(context);
  5. }
  6. public RoundRectImageViewB(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. public RoundRectImageViewB(Context context, AttributeSet attrs, int defStyle) {
  10. super(context, attrs, defStyle);
  11. }
  12. @Override
  13. protected void onDraw(Canvas canvas) {
  14. Drawable drawable = getDrawable();
  15. if (null != drawable) {
  16. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  17. //将newBitmap 转换成圆形
  18. Bitmap circleBitmap = toRoundCorner(rawBitmap, 30);
  19. final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  20. final Rect rectDes = new Rect(0, 0, getWidth(), getHeight());
  21. paint.reset();
  22. //绘制到画布上
  23. canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint);
  24. } else {
  25. super.onDraw(canvas);
  26. }
  27. }
  28. //将原始图像裁剪成正方形
  29. private Bitmap dealRawBitmap(Bitmap bitmap){
  30. int width = bitmap.getWidth();
  31. int height = bitmap.getHeight();
  32. //获取宽度
  33. int minWidth = width > height ? height:width ;
  34. //计算正方形的范围
  35. int leftTopX = (width - minWidth)/2;
  36. int leftTopY = (height - minWidth)/2;
  37. //裁剪成正方形
  38. Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false);
  39. return newBitmap;
  40. }
  41. //将头像按比例缩放
  42. private Bitmap scaleBitmap(Bitmap bitmap){
  43. int width = getWidth();
  44. //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误
  45. float scale = (float)width/(float)bitmap.getWidth();
  46. Matrix matrix = new Matrix();
  47. matrix.postScale(scale, scale);
  48. return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  49. }
  50. private Bitmap toRoundCorner(Bitmap bitmap, int radius) {
  51. //指定为 ARGB_4444 可以减小图片大小
  52. Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
  53. Canvas canvas = new Canvas(output);
  54. final int color = 0xff424242;
  55. final Rect rect = new Rect(0, 0,bitmap.getWidth(), bitmap.getHeight());
  56. paint.setAntiAlias(true);
  57. canvas.drawARGB(0, 0, 0, 0);
  58. paint.setColor(color);
  59. int x = bitmap.getWidth();
  60. canvas.drawRoundRect(new RectF(0,0,bitmap.getWidth(),bitmap.getHeight()), radius,radius, paint);
  61. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
  62. canvas.drawBitmap(bitmap, rect, rect, paint);
  63. return output;
  64. }
  65. }

通过BitmapShader方式实现

所有的绘制圆角的实现,推荐使用这个方法,不仅仅可以帮助我们实现圆角,连部分圆角都可以实现,比如顶部是两个圆角,底部是两个直角的图片。

首先介绍一下BitmapShader这个类,它作为纹理用于绘制一张图。新图可以是纹理图重复/镜像/边缘像素拉伸而绘制成的新图。这个类构造函数很简单,BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY),第一个参数是Bitmap,作为纹理图传入,tileX是指在水平方向上的绘制方式,tileY是指在竖直方向上的绘制方式。TileMode有三种属性,拉伸、重复、镜像。

使用BitmapShader绘制图的时候,是从画布的左上角开始绘制的。我们是使用拉伸的绘制模式,直接来看一下代码,了解处理过程。

  1. public class RoundRectImageViewC extends ImageView {
  2. private Paint paint = new Paint();
  3. public RoundRectImageViewC(Context context) {
  4. super(context);
  5. }
  6. public RoundRectImageViewC(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. public RoundRectImageViewC(Context context, AttributeSet attrs, int defStyle) {
  10. super(context, attrs, defStyle);
  11. }
  12. @Override
  13. protected void onDraw(Canvas canvas) {
  14. Drawable drawable = getDrawable();
  15. if (null != drawable) {
  16. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  17. Bitmap newBitmap = scaleBitmap(rawBitmap);
  18. Bitmap circleBitmap = toRoundCorner(newBitmap, 30);
  19. final Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  20. paint.reset();
  21. //绘制到画布上
  22. canvas.drawBitmap(circleBitmap, rect, rect, paint);
  23. } else {
  24. super.onDraw(canvas);
  25. }
  26. }
  27. //将头像按比例缩放
  28. private Bitmap scaleBitmap(Bitmap bitmap){
  29. int width = getWidth();
  30. int height = getHeight();
  31. //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误
  32. float scaleX = (float)width/(float)bitmap.getWidth();
  33. float scaleY = (float) height / (float) bitmap.getHeight();
  34. Matrix matrix = new Matrix();
  35. matrix.postScale(scaleX, scaleY);
  36. return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  37. }
  38. private Bitmap toRoundCorner(Bitmap bitmap, int radius) {
  39. // 初始化绘制纹理图
  40. BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
  41. //指定为 ARGB_4444 可以减小图片大小
  42. Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
  43. Canvas canvas = new Canvas(output);
  44. // 初始化画笔
  45. Paint paint = new Paint();
  46. paint.setAntiAlias(true);
  47. paint.setShader(bitmapShader);
  48. // 利用画笔将纹理图绘制到画布上面
  49. canvas.drawRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, paint);
  50. return output;
  51. }
  52. }

首先初始化了绘制的纹理图。然后初始化了画布和画笔,设置画笔绘制的纹理图,画笔在绘制图形时候就不是使用单纯的颜色绘制了。最后在利用画笔在画布上面绘制出圆形图片。

利用Rect实现缩放的RoundImageViewD(有问题,还未找到原因)

  1. public class RoundRectImageViewD extends ImageView {
  2. private Paint paint = new Paint();
  3. public RoundRectImageViewD(Context context) {
  4. super(context);
  5. }
  6. public RoundRectImageViewD(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. public RoundRectImageViewD(Context context, AttributeSet attrs, int defStyle) {
  10. super(context, attrs, defStyle);
  11. }
  12. @Override
  13. protected void onDraw(Canvas canvas) {
  14. Drawable drawable = getDrawable();
  15. if (null != drawable) {
  16. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  17. Bitmap circleBitmap = toRoundCorner(rawBitmap, 30);
  18. final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  19. final Rect rectDes = new Rect(0, 0, getWidth(), getHeight());
  20. paint.reset();
  21. //绘制到画布上
  22. canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint);
  23. } else {
  24. super.onDraw(canvas);
  25. }
  26. }
  27. private Bitmap toRoundCorner(Bitmap bitmap, int radius) {
  28. // 初始化绘制纹理图
  29. BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
  30. //指定为 ARGB_4444 可以减小图片大小
  31. Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
  32. Canvas canvas = new Canvas(output);
  33. // 初始化画笔
  34. Paint paint = new Paint();
  35. paint.setAntiAlias(true);
  36. paint.setShader(bitmapShader);
  37. // 利用画笔将纹理图绘制到画布上面
  38. canvas.drawRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, paint);
  39. return output;
  40. }
  41. }

利用BitmapShader还可以实现很多其他样式的效果,有下面几种:

具体请参考:Android圆角图片和圆形图片实现总结

通过画布裁剪的方式实现

关于画布裁剪的知识,建议阅读:Canvas的裁剪

  1. public class RoundRectImageViewE extends ImageView {
  2. private Paint paint = new Paint();
  3. public RoundRectImageViewE(Context context) {
  4. super(context);
  5. }
  6. public RoundRectImageViewE(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. public RoundRectImageViewE(Context context, AttributeSet attrs, int defStyle) {
  10. super(context, attrs, defStyle);
  11. }
  12. @Override
  13. protected void onDraw(Canvas canvas) {
  14. Drawable drawable = getDrawable();
  15. if (null != drawable) {
  16. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  17. //处理Bitmap 转成正方形
  18. Bitmap newBitmap = dealRawBitmap(rawBitmap);
  19. //将newBitmap 转换成圆形
  20. Bitmap circleBitmap = toRoundCorner(newBitmap,30);
  21. final Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  22. paint.reset();
  23. //绘制到画布上
  24. canvas.drawBitmap(circleBitmap, rect, rect, paint);
  25. } else {
  26. super.onDraw(canvas);
  27. }
  28. }
  29. //将原始图像裁剪成正方形
  30. private Bitmap dealRawBitmap(Bitmap bitmap){
  31. int width = bitmap.getWidth();
  32. int height = bitmap.getHeight();
  33. //获取宽度
  34. int minWidth = width > height ? height:width ;
  35. //计算正方形的范围
  36. int leftTopX = (width - minWidth)/2;
  37. int leftTopY = (height - minWidth)/2;
  38. //裁剪成正方形
  39. Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false);
  40. return scaleBitmap(newBitmap);
  41. }
  42. //将头像按比例缩放
  43. private Bitmap scaleBitmap(Bitmap bitmap){
  44. int width = getWidth();
  45. int height = getHeight();
  46. //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误
  47. float scaleX = (float)width/(float)bitmap.getWidth();
  48. float scaleY = (float) height / (float) bitmap.getHeight();
  49. Matrix matrix = new Matrix();
  50. matrix.postScale(scaleX, scaleY);
  51. return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  52. }
  53. private Bitmap toRoundCorner(Bitmap bitmap,int radius) {
  54. //指定为 ARGB_4444 可以减小图片大小
  55. Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
  56. Canvas canvas = new Canvas(output);
  57. // 初始化画笔
  58. Paint paint = new Paint();
  59. paint.setAntiAlias(true);
  60. paint.setFilterBitmap(true);
  61. Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
  62. Path path = new Path();
  63. path.addRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, Path.Direction.CW);
  64. canvas.clipPath(path, Region.Op.INTERSECT);
  65. canvas.drawBitmap(bitmap,rect,rect,paint);
  66. return output;
  67. }
  68. }

通过Rect缩放实现的RoundRectImageViewF。

  1. /**
  2. * 圆形控件
  3. *
  4. * @author zhangyan
  5. *
  6. */
  7. public class RoundRectImageViewF extends ImageView {
  8. private Paint paint = new Paint();
  9. public RoundRectImageViewF(Context context) {
  10. super(context);
  11. }
  12. public RoundRectImageViewF(Context context, AttributeSet attrs) {
  13. super(context, attrs);
  14. }
  15. public RoundRectImageViewF(Context context, AttributeSet attrs, int defStyle) {
  16. super(context, attrs, defStyle);
  17. }
  18. @Override
  19. protected void onDraw(Canvas canvas) {
  20. Drawable drawable = getDrawable();
  21. if (null != drawable) {
  22. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  23. //处理Bitmap 转成正方形
  24. Bitmap newBitmap = dealRawBitmap(rawBitmap);
  25. //将newBitmap 转换成圆形
  26. Bitmap circleBitmap = toRoundCorner(newBitmap,30);
  27. final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  28. final Rect rectDes = new Rect(0, 0, getWidth(), getHeight());
  29. paint.reset();
  30. //绘制到画布上
  31. canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint);
  32. } else {
  33. super.onDraw(canvas);
  34. }
  35. }
  36. //将原始图像裁剪成正方形
  37. private Bitmap dealRawBitmap(Bitmap bitmap){
  38. int width = bitmap.getWidth();
  39. int height = bitmap.getHeight();
  40. //获取宽度
  41. int minWidth = width > height ? height:width ;
  42. //计算正方形的范围
  43. int leftTopX = (width - minWidth)/2;
  44. int leftTopY = (height - minWidth)/2;
  45. //裁剪成正方形
  46. Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false);
  47. return newBitmap;
  48. }
  49. private Bitmap toRoundCorner(Bitmap bitmap,int radius) {
  50. //指定为 ARGB_4444 可以减小图片大小
  51. Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
  52. Canvas canvas = new Canvas(output);
  53. // 初始化画笔
  54. Paint paint = new Paint();
  55. paint.setAntiAlias(true);
  56. paint.setFilterBitmap(true);
  57. Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
  58. Path path = new Path();
  59. path.addRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, Path.Direction.CW);
  60. canvas.clipPath(path, Region.Op.INTERSECT);
  61. canvas.drawBitmap(bitmap,rect,rect,paint);
  62. return output;
  63. }
  64. }

在面试的过程中阿里的面试官说这种方案会新建一个Bitmap,所以可能会导致内存占用率过高。我们可以改进上面的裁剪的实现方式,直接在原来的画布上进行裁剪,避免创建新的的Bitmap,改进后的代码如下所示:

  1. /**
  2. * 圆形控件
  3. *
  4. * @author zhangyan
  5. *
  6. */
  7. public class RoundRectImageViewE extends ImageView {
  8. private Paint paint = new Paint();
  9. public RoundRectImageViewE(Context context) {
  10. super(context);
  11. }
  12. public RoundRectImageViewE(Context context, AttributeSet attrs) {
  13. super(context, attrs);
  14. }
  15. public RoundRectImageViewE(Context context, AttributeSet attrs, int defStyle) {
  16. super(context, attrs, defStyle);
  17. }
  18. @Override
  19. protected void onDraw(Canvas canvas) {
  20. Drawable drawable = getDrawable();
  21. if (null != drawable) {
  22. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  23. //处理Bitmap 转成正方形
  24. Bitmap circleBitmap = dealRawBitmap(rawBitmap);
  25. Path path = new Path();
  26. path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), 30, 30, Path.Direction.CW);
  27. canvas.clipPath(path, Region.Op.INTERSECT);
  28. Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  29. paint.reset();
  30. //绘制到画布上
  31. canvas.drawBitmap(circleBitmap, rect, rect, paint);
  32. } else {
  33. super.onDraw(canvas);
  34. }
  35. }
  36. //将原始图像裁剪成正方形
  37. private Bitmap dealRawBitmap(Bitmap bitmap){
  38. int width = bitmap.getWidth();
  39. int height = bitmap.getHeight();
  40. //获取宽度
  41. int minWidth = width > height ? height:width ;
  42. //计算正方形的范围
  43. int leftTopX = (width - minWidth)/2;
  44. int leftTopY = (height - minWidth)/2;
  45. //裁剪成正方形
  46. Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false);
  47. return scaleBitmap(newBitmap);
  48. }
  49. //将头像按比例缩放
  50. private Bitmap scaleBitmap(Bitmap bitmap){
  51. int width = getWidth();
  52. int height = getHeight();
  53. //一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误
  54. float scaleX = (float)width/(float)bitmap.getWidth();
  55. float scaleY = (float) height / (float) bitmap.getHeight();
  56. Matrix matrix = new Matrix();
  57. matrix.postScale(scaleX, scaleY);
  58. return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
  59. }
  60. }

(实现的圆角矩形没有任何问题)

  1. public class RoundRectImageViewF extends ImageView {
  2. private Paint paint = new Paint();
  3. public RoundRectImageViewF(Context context) {
  4. super(context);
  5. }
  6. public RoundRectImageViewF(Context context, AttributeSet attrs) {
  7. super(context, attrs);
  8. }
  9. public RoundRectImageViewF(Context context, AttributeSet attrs, int defStyle) {
  10. super(context, attrs, defStyle);
  11. }
  12. @Override
  13. protected void onDraw(Canvas canvas) {
  14. Drawable drawable = getDrawable();
  15. if (null != drawable) {
  16. Bitmap rawBitmap =((BitmapDrawable)drawable).getBitmap();
  17. //处理Bitmap 转成正方形
  18. Bitmap circleBitmap = dealRawBitmap(rawBitmap);
  19. Path path = new Path();
  20. path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), 30, 30, Path.Direction.CW);
  21. canvas.clipPath(path, Region.Op.INTERSECT);
  22. final Rect rectSrc = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());
  23. final Rect rectDes = new Rect(0, 0, getWidth(), getHeight());
  24. paint.reset();
  25. //绘制到画布上
  26. canvas.drawBitmap(circleBitmap, rectSrc, rectDes, paint);
  27. } else {
  28. super.onDraw(canvas);
  29. }
  30. }
  31. //将原始图像裁剪成正方形
  32. private Bitmap dealRawBitmap(Bitmap bitmap){
  33. int width = bitmap.getWidth();
  34. int height = bitmap.getHeight();
  35. //获取宽度
  36. int minWidth = width > height ? height:width ;
  37. //计算正方形的范围
  38. int leftTopX = (width - minWidth)/2;
  39. int leftTopY = (height - minWidth)/2;
  40. //裁剪成正方形
  41. Bitmap newBitmap = Bitmap.createBitmap(bitmap,leftTopX,leftTopY,minWidth,minWidth,null,false);
  42. return newBitmap;
  43. }
  44. }

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参数(三)

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注