Android 圆形/圆角图片的方法
Android 圆形/圆角图片的方法
眼下网上有非常多圆角图片的实例,Github上也有一些成熟的项目。之前做项目,为了稳定高效都是选用Github上的项目直接用。但这样的结束也是Android开发必备技能 。所以今天就来简单研究一下该技术,分享给大家。
预备知识:
Xfermode介绍:
以下是Android ApiDemo里的“Xfermodes”实例,效果图。

Xfermode有三个子类。结构例如以下:
1.publicclass2.Xfermode3.extendsObject4.java.lang.Object5.?
android.graphics.Xfermode
6.Known Direct Subclasses7.AvoidXfermode, PixelXorXfermode, PorterDuffXfermodeAvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面画图(或者仅仅在它上面画图)。
PixelXorXfermode 当覆盖已有的颜色时。应用一个简单的像素异或操作。
PorterDuffXfermode 这是一个很强大的转换模式,使用它,能够使用图像合成的16条Porter-Duff规则的随意一条来控制Paint怎样与已有的Canvas图像进行交互。
上面图片种显示的16种模式介绍例如以下:
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示。上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。
下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层所有区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层所有。点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层所有区域,交集部分变为透明色
了解了上面的知识点后,我们依据上面的知识点先来实现第一种圆角图片制作方式:
原图:

先看这一段代码
01.privateImageView mImg;02. 03.@Override04.protectedvoidonCreate(Bundle savedInstanceState) {05.super.onCreate(savedInstanceState);06.setContentView(R.layout.activity_main);07.mImg = (ImageView) findViewById(R.id.img);08. 09.//获得imageview中设置的图片10.BitmapDrawable drawable = (BitmapDrawable) mImg.getDrawable();11.Bitmap bmp = drawable.getBitmap();12.//获得图片的宽,并创建结果bitmap13.intwidth = bmp.getWidth();14.Bitmap resultBmp = Bitmap.createBitmap(width, width,15.Bitmap.Config.ARGB_8888);16.Paint paint =newPaint();17.Canvas canvas =newCanvas(resultBmp);18.//画圆19.canvas.drawCircle(width /2, width /
2, width /2, paint);20.paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));//
选择交集去上层图片21.canvas.drawBitmap(bmp,0,
0, paint);22.mImg.setImageBitmap(resultBmp);23.bmp.recycle();24. 25.}通过执行上面的代码,我们得出的结果例如以下:

大家看到这是我们须要的结果。但是这样做可能导致OutOfMomery异常。假如图片非常大或者你可能并不是通过ImageView的getDrawable获得图像,而是直接Decode一张非常大的图片载入到内存,你会发现可能会出现异常。我们做一下改变。
01.privatestaticfinal String TAG = "RoundImage";02.privateImageView mImg;03. 04.@Override05.protectedvoidonCreate(Bundle savedInstanceState) {06.super.onCreate(savedInstanceState);07.setContentView(R.layout.activity_main);08.mImg = (ImageView) findViewById(R.id.img);09.// 裁剪图片10.BitmapFactory.Options options =newBitmapFactory.Options();11.options.inJustDecodeBounds =true;12.BitmapFactory13..decodeResource(getResources(), R.drawable.avatar, options);14.Log.d(TAG,"original outwidth: "+ options.outWidth);15.// 此宽度是目标ImageView希望的大小,你能够自己定义ImageView。然后获得ImageView的宽度。
16.intdstWidth =
150;17.// 我们须要载入的图片可能非常大,我们先对原有的图片进行裁剪18.intsampleSize = calculateInSampleSize(options, dstWidth, dstWidth);19.options.inSampleSize = sampleSize;20.options.inJustDecodeBounds =false;21.Log.d(TAG,"sample size: "+ sampleSize);22.Bitmap bmp = BitmapFactory.decodeResource(getResources(),23.R.drawable.avatar, options);24. 25.// 绘制图片26.Bitmap resultBmp = Bitmap.createBitmap(dstWidth, dstWidth,27.Bitmap.Config.ARGB_8888);28.Paint paint =newPaint();29.paint.setAntiAlias(true);30.Canvas canvas =newCanvas(resultBmp);31.// 画圆32.canvas.drawCircle(dstWidth /2, dstWidth /
2, dstWidth /2, paint);33.// 选择交集去上层图片34.paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));35.canvas.drawBitmap(bmp,newRect(0,0, bmp.getWidth(), bmp.getWidth()),36.newRect(0,0,
dstWidth, dstWidth), paint);37.mImg.setImageBitmap(resultBmp);38.bmp.recycle();39.}40. 41.privateintcalculateInSampleSize(BitmapFactory.Options options,42.intreqWidth,
int reqHeight) {43.// Raw height and width of image44.finalintheight = options.outHeight;45.finalintwidth = options.outWidth;46.intinSampleSize =
1;47. 48.if(height > reqHeight || width > reqWidth) {49. 50.finalinthalfHeight = height / 2;51.finalinthalfWidth = width / 2;52. 53.// Calculate the largest inSampleSize value that is a power of 2 and54.// keeps both55.// height and width larger than the requested height and width.56.while((halfHeight / inSampleSize) > reqHeight57.&& (halfWidth / inSampleSize) > reqWidth) {58.inSampleSize *=2;59.}60.}61.returninSampleSize;62.}再来看一下效果:

上面提供了一种方式,很多其它细节,须要你自己去优化,以下介绍另外一种绘制圆角图片的方式。
首先我们须要了解一个类BitmapShader
引用的介绍例如以下:
public BitmapShader(Bitmap bitmap,Shader.TileMode tileX,Shader.TileMode tileY)
调用这种方法来产生一个画有一个位图的渲染器(Shader)。
bitmap 在渲染器内使用的位图
tileX The tiling mode for x to draw the bitmap in. 在位图上X方向花砖模式
tileY The tiling mode for y to draw the bitmap in. 在位图上Y方向花砖模式
TileMode:(一共同拥有三种)
CLAMP :假设渲染器超出原始边界范围。会复制范围内边缘染色。
REPEAT :横向和纵向的反复渲染器图片,平铺。
MIRROR :横向和纵向的反复渲染器图片,这个和REPEAT 反复方式不一样,他是以镜像方式平铺。
知道这个原理后,我们贴出相应的代码:
01.publicclassCircleImageView extendsImageView {02. 03.privatestaticfinal String TAG = CircleImageView.class.getSimpleName();04.privatePaint mBitmapPaint =
new Paint();05.privateintmRadius;06. 07.publicCircleImageView(Context context, AttributeSet attrs,
intdefStyleAttr) {08.super(context, attrs, defStyleAttr);09.init();10.}11. 12.publicCircleImageView(Context context, AttributeSet attrs) {13.super(context, attrs);14.init();15.}16. 17.publicCircleImageView(Context context) {18.super(context);19.init();20.}21. 22.privatevoidinit() {23.BitmapDrawable drawable = (BitmapDrawable) getDrawable();24.if(drawable ==
null) {25.Log.i(TAG,"drawable: null");26.return;27.}28.Bitmap bmp = drawable.getBitmap();29.BitmapShader shader =newBitmapShader(bmp, TileMode.CLAMP,30.TileMode.CLAMP);31.mBitmapPaint.setShader(shader);32.mBitmapPaint.setAntiAlias(true);33.invalidate();34.}35. 36.@Override37.protectedvoidonDraw(Canvas canvas) {38.if(getDrawable() ==
null) {39.return;40.}41.mRadius = Math.min(getWidth()/2, getHeight()/2);42.canvas.drawCircle(getWidth() /2, getHeight() /
2, mRadius,43.mBitmapPaint);44.}45. 46.}是不是挺简单的
结果我就不显示了,跟上面的一样。
上面也是最原始的代码,文章的结尾贴出一份完整优化过的代码共大家參考例如以下:
001.publicclassCircleImageView extendsImageView {002. 003.privatestaticfinal ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;004. 005.privatestaticfinal Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;006.privatestaticfinal int
COLORDRAWABLE_DIMENSION = 1;007. 008.privatestaticfinal int
DEFAULT_BORDER_WIDTH = 0;009.privatestaticfinal int
DEFAULT_BORDER_COLOR = Color.BLACK;010. 011.privatefinalRectF mDrawableRect = newRectF();012.privatefinalRectF mBorderRect = new
RectF();013. 014.privatefinalMatrix mShaderMatrix = newMatrix();015.privatefinalPaint mBitmapPaint = new
Paint();016.privatefinalPaint mBorderPaint = new
Paint();017. 018.privateintmBorderColor = DEFAULT_BORDER_COLOR;019.privateintmBorderWidth = DEFAULT_BORDER_WIDTH;020. 021.privateBitmap mBitmap;022.privateBitmapShader mBitmapShader;023.privateintmBitmapWidth;024.privateintmBitmapHeight;025. 026.privatefloatmDrawableRadius;027.privatefloatmBorderRadius;028. 029.privatebooleanmReady;030.privatebooleanmSetupPending;031. 032.publicCircleImageView(Context context) {033.super(context);034. 035.init();036.}037. 038.publicCircleImageView(Context context, AttributeSet attrs) {039.this(context, attrs,0);040.}041. 042.publicCircleImageView(Context context, AttributeSet attrs,
intdefStyle) {043.super(context, attrs, defStyle);044. 045.TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle,0);046. 047.mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);048.mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);049. 050.a.recycle();051. 052.init();053.}054. 055.privatevoidinit() {056.super.setScaleType(SCALE_TYPE);057.mReady =true;058. 059.if(mSetupPending) {060.setup();061.mSetupPending =false;062.}063.}064. 065.@Override066.publicScaleType getScaleType() {067.returnSCALE_TYPE;068.}069. 070.@Override071.publicvoidsetScaleType(ScaleType scaleType) {072.if(scaleType != SCALE_TYPE) {073.thrownewIllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));074.}075.}076. 077.@Override078.protectedvoidonDraw(Canvas canvas) {079.if(getDrawable() ==
null) {080.return;081.}082. 083.canvas.drawCircle(getWidth() /2, getHeight() /
2, mDrawableRadius, mBitmapPaint);084.if(mBorderWidth !=
0) {085.canvas.drawCircle(getWidth() /2, getHeight() /
2, mBorderRadius, mBorderPaint);086.}087.}088. 089.@Override090.protectedvoidonSizeChanged(intw,
int h, intoldw, intoldh) {091.super.onSizeChanged(w, h, oldw, oldh);092.setup();093.}094. 095.publicintgetBorderColor() {096.returnmBorderColor;097.}098. 099.publicvoidsetBorderColor(intborderColor) {100.if(borderColor == mBorderColor) {101.return;102.}103. 104.mBorderColor = borderColor;105.mBorderPaint.setColor(mBorderColor);106.invalidate();107.}108. 109.publicintgetBorderWidth() {110.returnmBorderWidth;111.}112. 113.publicvoidsetBorderWidth(intborderWidth) {114.if(borderWidth == mBorderWidth) {115.return;116.}117. 118.mBorderWidth = borderWidth;119.setup();120.}121. 122.@Override123.publicvoidsetImageBitmap(Bitmap bm) {124.super.setImageBitmap(bm);125.mBitmap = bm;126.setup();127.}128. 129.@Override130.publicvoidsetImageDrawable(Drawable drawable) {131.super.setImageDrawable(drawable);132.mBitmap = getBitmapFromDrawable(drawable);133.setup();134.}135. 136.@Override137.publicvoidsetImageResource(intresId) {138.super.setImageResource(resId);139.mBitmap = getBitmapFromDrawable(getDrawable());140.setup();141.}142. 143.@Override144.publicvoidsetImageURI(Uri uri) {145.super.setImageURI(uri);146.mBitmap = getBitmapFromDrawable(getDrawable());147.setup();148.}149. 150.privateBitmap getBitmapFromDrawable(Drawable drawable) {151.if(drawable ==
null) {152.returnnull;153.}154. 155.if(drawable
instanceof BitmapDrawable) {156.return((BitmapDrawable) drawable).getBitmap();157.}158. 159.try{160.Bitmap bitmap;161. 162.if(drawable
instanceof ColorDrawable) {163.bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);164.}else{165.bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);166.}167. 168.Canvas canvas =newCanvas(bitmap);169.drawable.setBounds(0,0,
canvas.getWidth(), canvas.getHeight());170.drawable.draw(canvas);171.returnbitmap;172.}catch(OutOfMemoryError e) {173.returnnull;174.}175.}176. 177.privatevoidsetup() {178.if(!mReady) {179.mSetupPending =true;180.return;181.}182. 183.if(mBitmap ==
null) {184.return;185.}186. 187.mBitmapShader =newBitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);188. 189.mBitmapPaint.setAntiAlias(true);190.mBitmapPaint.setShader(mBitmapShader);191. 192.mBorderPaint.setStyle(Paint.Style.STROKE);193.mBorderPaint.setAntiAlias(true);194.mBorderPaint.setColor(mBorderColor);195.mBorderPaint.setStrokeWidth(mBorderWidth);196. 197.mBitmapHeight = mBitmap.getHeight();198.mBitmapWidth = mBitmap.getWidth();199. 200.mBorderRect.set(0,0,
getWidth(), getHeight());201.mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) /2,
(mBorderRect.width() - mBorderWidth) /2);202. 203.mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);204.mDrawableRadius = Math.min(mDrawableRect.height() /2, mDrawableRect.width()
/ 2);205. 206.updateShaderMatrix();207.invalidate();208.}209. 210.privatevoidupdateShaderMatrix() {211.floatscale;212.floatdx =
0;213.floatdy =
0;214. 215.mShaderMatrix.set(null);216. 217.if(mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {218.scale = mDrawableRect.height() / (float) mBitmapHeight;219.dx = (mDrawableRect.width() - mBitmapWidth * scale) *0.5f;220.}else{221.scale = mDrawableRect.width() / (float) mBitmapWidth;222.dy = (mDrawableRect.height() - mBitmapHeight * scale) *0.5f;223.}224. 225.mShaderMatrix.setScale(scale, scale);226.mShaderMatrix.postTranslate((int) (dx +0.5f)
+ mBorderWidth, (int) (dy +0.5f) + mBorderWidth);227. 228.mBitmapShader.setLocalMatrix(mShaderMatrix);229.}230. 231.}Android 圆形/圆角图片的方法的更多相关文章
- 安卓图片载入之使用universalimageloader载入圆形圆角图片
前言 话说这universalimageloader载入图片对搞过2年安卓程序都是用烂了再熟悉只是了.就是安卓新手也是百度就会有一大堆东西出来,今天为什么这里还要讲使用universalimagelo ...
- Android实现圆形圆角图片
本文主要使用两种方法实现图形圆角图片 自定View加上使用Xfermode实现 Shader实现 自定View加上使用Xfermode实现 /** * 根据原图和变长绘制圆形图片 * * @param ...
- Android 简单的图片缩放方法
很简单的一个图片缩放方法,注意要比例设置正确否则可能会内存溢出 相关问题 java.lang.IllegalArgumentException: bitmap size exceeds 32bits ...
- CircleImageManager——圆形 / 圆角图片的工具类
这个类可以实现圆角,或者是圆形图片的操作. CircleImageManager.java package com.kale.utils; import android.content.Context ...
- Android 获得各处图片的方法
<pre name="code" class="java">//1,已将图片保存到drawable目录下 //通过图片id获得Drawable Re ...
- Android BitmapShader 实战 实现圆形、圆角图片
转载自:http://blog.csdn.net/lmj623565791/article/details/41967509 1.概述 记得初学那会写过一篇博客Android 完美实现图片圆角和圆形( ...
- 【转】Android BitmapShader 实战 实现圆形、圆角图片
转载自:http://blog.csdn.net/lmj623565791/article/details/41967509 1.概述 记得初学那会写过一篇博客Android 完美实现图片圆角和圆形( ...
- Android_BitmapShader实现圆形、圆角图片
转:http://blog.csdn.net/lmj623565791/article/details/41967509,本文出自:[张鸿洋的博客] 1.概述 记得初学那会写过一篇博客Android ...
- android图片处理方法
Java代码 //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ...
随机推荐
- 迅为工业级arm开发板i.MX6DL开发板软件硬件全开源
i.MX6是基于ARM Cortex™-A9架构的高扩展性多核系列应用处理器,促进了如高稳定性工业平板电脑.差异化智能本.前装车载中控系统和超高清电子书阅读器等新一代应用的发展.强劲的3D图形加速引擎 ...
- Hibernate的入门使用
数据在各个层次之间流转,在流转过程中会发生数据类型转换等一系列的交互问题.java与html的交互解决方案是struts2提供的OGNL(对象导航图语言),而java与数据库之间的技术解决方案是ORM ...
- 部分cocoscreator左右移动代码
cc.Class({extends: cc.Component, properties: { // 主角跳跃高度 jumpHeight: 0, // 主角跳跃持续时间 jumpDuration: 0, ...
- MIPS的寄存器、指令和寻址方式的分类
MIPS的32个寄存器 助记符 编号 作用 zero 0 恒为0 at 1 (assembly temporary)保留给汇编器使用 v0,v1 2-3 (values)子程序返回,即函数调用时的返回 ...
- CAD参数绘制多行文字(com接口)
在CAD设计时,需要绘制多行文字,用户可以设置设置绘制文字的高度等属性. 主要用到函数说明: _DMxDrawX::DrawMText 绘制一个多行文字.详细说明如下: 参数 说明 DOUBLE dP ...
- Laravel Excel安装及最简单使用
官网:https://docs.laravel-excel.com/ 1.安装 1.1.安装要求: PHP: ^7.0 Laravel: ^5.5 PhpSpreadsheet: ^1.6 ...
- vue+webpack静态资源路径引用
处理静态资产 你可能已经注意到,在项目结构中我们有两个静态资产目录:src/assets和static/.他们之间有什么区别? 要回答这个问题,我们首先需要了解Webpack如何处理静态资产.在*.v ...
- 解决idea开启tomcat报Configuration Error: deployment source 'xxx:war exploded' is not valid错
这个问题比较棘手, 出错了的时候Tomcat服务器不能正常运行, 导致网页无法打开, 小组成员都说"Tomcat炸了"! 好在这个这个xml配置文件是自动生成的,重新生成一下就好了 ...
- [Luogu] P4910 帕秋莉的手环
题目背景 帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里.不仅擅长许多魔法,还每天都会开发出新的魔法.只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦. 她所用的属性魔法,主要是生命和 ...
- [Python3网络爬虫开发实战] 1.2.3-ChromeDriver的安装
前面我们成功安装好了Selenium库,但是它是一个自动化测试工具,需要浏览器来配合使用,本节中我们就介绍一下Chrome浏览器及ChromeDriver驱动的配置. 首先,下载Chrome浏览器,方 ...