Android 圆形/圆角图片的方法

时间:2022-11-09 00:24:56

Android 圆形/圆角图片的方法

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

预备知识:

Xfermode介绍:

以下是Android ApiDemo里的“Xfermodes”实例,效果图。

Android 圆形/圆角图片的方法

Xfermode有三个子类。结构例如以下:

1.publicclass
2.Xfermode
3.extendsObject
4.java.lang.Object
5.?

android.graphics.Xfermode

6.Known Direct Subclasses
7.AvoidXfermode, PixelXorXfermode, PorterDuffXfermode

AvoidXfermode 指定了一个颜色和容差,强制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

取两图层所有区域,交集部分变为透明色

了解了上面的知识点后,我们依据上面的知识点先来实现第一种圆角图片制作方式:

原图:

Android 圆形/圆角图片的方法

先看这一段代码

01.privateImageView mImg;
02. 
03.@Override
04.protectedvoid
onCreate(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.//获得图片的宽,并创建结果bitmap
13.intwidth = bmp.getWidth();
14.Bitmap resultBmp = Bitmap.createBitmap(width, width,
15.Bitmap.Config.ARGB_8888);
16.Paint paint =new
Paint();
17.Canvas canvas =new
Canvas(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.}

通过执行上面的代码,我们得出的结果例如以下:

Android 圆形/圆角图片的方法

大家看到这是我们须要的结果。但是这样做可能导致OutOfMomery异常。假如图片非常大或者你可能并不是通过ImageView的getDrawable获得图像,而是直接Decode一张非常大的图片载入到内存,你会发现可能会出现异常。我们做一下改变。

01.privatestatic
final String TAG = "RoundImage";
02.privateImageView mImg;
03. 
04.@Override
05.protectedvoid
onCreate(Bundle savedInstanceState) {
06.super.onCreate(savedInstanceState);
07.setContentView(R.layout.activity_main);
08.mImg = (ImageView) findViewById(R.id.img);
09.// 裁剪图片
10.BitmapFactory.Options options =new
BitmapFactory.Options();
11.options.inJustDecodeBounds =true;
12.BitmapFactory
13..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 =new
Paint();
29.paint.setAntiAlias(true);
30.Canvas canvas =new
Canvas(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,new
Rect(0,0, bmp.getWidth(), bmp.getWidth()),
36.newRect(0,0,
dstWidth, dstWidth), paint);
37.mImg.setImageBitmap(resultBmp);
38.bmp.recycle();
39.}
40. 
41.privateint
calculateInSampleSize(BitmapFactory.Options options,
42.intreqWidth,
int reqHeight) {
43.// Raw height and width of image
44.finalint
height = options.outHeight;
45.finalint
width = options.outWidth;
46.intinSampleSize =
1;
47. 
48.if(height > reqHeight || width > reqWidth) {
49. 
50.finalint
halfHeight = height / 2;
51.finalint
halfWidth = width / 2;
52. 
53.// Calculate the largest inSampleSize value that is a power of 2 and
54.// keeps both
55.// height and width larger than the requested height and width.
56.while((halfHeight / inSampleSize) > reqHeight
57.&& (halfWidth / inSampleSize) > reqWidth) {
58.inSampleSize *=2;
59.}
60.}
61.returninSampleSize;
62.}

再来看一下效果:

Android 圆形/圆角图片的方法

上面提供了一种方式,很多其它细节,须要你自己去优化,以下介绍另外一种绘制圆角图片的方式。

首先我们须要了解一个类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.publicclass
CircleImageView extendsImageView {
02. 
03.privatestatic
final String TAG = CircleImageView.class.getSimpleName();
04.privatePaint mBitmapPaint =
new Paint();
05.privateint
mRadius;
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.privatevoid
init() {
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 =new
BitmapShader(bmp, TileMode.CLAMP,
30.TileMode.CLAMP);
31.mBitmapPaint.setShader(shader);
32.mBitmapPaint.setAntiAlias(true);
33.invalidate();
34.}
35. 
36.@Override
37.protectedvoid
onDraw(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.publicclass
CircleImageView extendsImageView {
002. 
003.privatestatic
final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
004. 
005.privatestatic
final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
006.privatestatic
final int
COLORDRAWABLE_DIMENSION =
1;
007. 
008.privatestatic
final int
DEFAULT_BORDER_WIDTH =
0;
009.privatestatic
final int
DEFAULT_BORDER_COLOR = Color.BLACK;
010. 
011.privatefinal
RectF mDrawableRect = new
RectF();
012.privatefinal
RectF mBorderRect = new
RectF();
013. 
014.privatefinal
Matrix mShaderMatrix = new
Matrix();
015.privatefinal
Paint mBitmapPaint = new
Paint();
016.privatefinal
Paint mBorderPaint = new
Paint();
017. 
018.privateint
mBorderColor = DEFAULT_BORDER_COLOR;
019.privateint
mBorderWidth = DEFAULT_BORDER_WIDTH;
020. 
021.privateBitmap mBitmap;
022.privateBitmapShader mBitmapShader;
023.privateint
mBitmapWidth;
024.privateint
mBitmapHeight;
025. 
026.privatefloat
mDrawableRadius;
027.privatefloat
mBorderRadius;
028. 
029.privateboolean
mReady;
030.privateboolean
mSetupPending;
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.privatevoid
init() {
056.super.setScaleType(SCALE_TYPE);
057.mReady =true;
058. 
059.if(mSetupPending) {
060.setup();
061.mSetupPending =false;
062.}
063.}
064. 
065.@Override
066.publicScaleType getScaleType() {
067.returnSCALE_TYPE;
068.}
069. 
070.@Override
071.publicvoid
setScaleType(ScaleType scaleType) {
072.if(scaleType != SCALE_TYPE) {
073.thrownew
IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
074.}
075.}
076. 
077.@Override
078.protectedvoid
onDraw(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.@Override
090.protectedvoid
onSizeChanged(intw,
int h, int
oldw, intoldh) {
091.super.onSizeChanged(w, h, oldw, oldh);
092.setup();
093.}
094. 
095.publicint
getBorderColor() {
096.returnmBorderColor;
097.}
098. 
099.publicvoid
setBorderColor(intborderColor) {
100.if(borderColor == mBorderColor) {
101.return;
102.}
103. 
104.mBorderColor = borderColor;
105.mBorderPaint.setColor(mBorderColor);
106.invalidate();
107.}
108. 
109.publicint
getBorderWidth() {
110.returnmBorderWidth;
111.}
112. 
113.publicvoid
setBorderWidth(intborderWidth) {
114.if(borderWidth == mBorderWidth) {
115.return;
116.}
117. 
118.mBorderWidth = borderWidth;
119.setup();
120.}
121. 
122.@Override
123.publicvoid
setImageBitmap(Bitmap bm) {
124.super.setImageBitmap(bm);
125.mBitmap = bm;
126.setup();
127.}
128. 
129.@Override
130.publicvoid
setImageDrawable(Drawable drawable) {
131.super.setImageDrawable(drawable);
132.mBitmap = getBitmapFromDrawable(drawable);
133.setup();
134.}
135. 
136.@Override
137.publicvoid
setImageResource(intresId) {
138.super.setImageResource(resId);
139.mBitmap = getBitmapFromDrawable(getDrawable());
140.setup();
141.}
142. 
143.@Override
144.publicvoid
setImageURI(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 =new
Canvas(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.privatevoid
setup() {
178.if(!mReady) {
179.mSetupPending =true;
180.return;
181.}
182. 
183.if(mBitmap ==
null) {
184.return;
185.}
186. 
187.mBitmapShader =new
BitmapShader(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.privatevoid
updateShaderMatrix() {
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 圆形/圆角图片的方法的更多相关文章

  1. 安卓图片载入之使用universalimageloader载入圆形圆角图片

    前言 话说这universalimageloader载入图片对搞过2年安卓程序都是用烂了再熟悉只是了.就是安卓新手也是百度就会有一大堆东西出来,今天为什么这里还要讲使用universalimagelo ...

  2. Android实现圆形圆角图片

    本文主要使用两种方法实现图形圆角图片 自定View加上使用Xfermode实现 Shader实现 自定View加上使用Xfermode实现 /** * 根据原图和变长绘制圆形图片 * * @param ...

  3. Android 简单的图片缩放方法

    很简单的一个图片缩放方法,注意要比例设置正确否则可能会内存溢出 相关问题 java.lang.IllegalArgumentException: bitmap size exceeds 32bits ...

  4. CircleImageManager——圆形 / 圆角图片的工具类

    这个类可以实现圆角,或者是圆形图片的操作. CircleImageManager.java package com.kale.utils; import android.content.Context ...

  5. Android 获得各处图片的方法

    <pre name="code" class="java">//1,已将图片保存到drawable目录下 //通过图片id获得Drawable Re ...

  6. Android BitmapShader 实战 实现圆形、圆角图片

    转载自:http://blog.csdn.net/lmj623565791/article/details/41967509 1.概述 记得初学那会写过一篇博客Android 完美实现图片圆角和圆形( ...

  7. 【转】Android BitmapShader 实战 实现圆形、圆角图片

    转载自:http://blog.csdn.net/lmj623565791/article/details/41967509 1.概述 记得初学那会写过一篇博客Android 完美实现图片圆角和圆形( ...

  8. Android&lowbar;BitmapShader实现圆形、圆角图片

    转:http://blog.csdn.net/lmj623565791/article/details/41967509,本文出自:[张鸿洋的博客] 1.概述 记得初学那会写过一篇博客Android ...

  9. android图片处理方法

    Java代码 //压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ...

随机推荐

  1. reactjs 注意点

    render的return return前要留一空行 return的括号要分别各占一行,不能与html同行 return中的html必须要有顶层容器包裹 return中的循环不能用for,改用map方 ...

  2. NetBeansRCP-添加/修改NetBeans的JVM启动参数

    NetBeans运行的速度实在是不敢恭维.还好机器配置还可以,修改其JVM启动参数命令行,以期运行的更加顺畅. 那么如何修改NetBeans IDE的JVM参数呢? 1.到NetBeans IDE的安 ...

  3. c&num;中实现登陆窗口(无需隐藏)

    C#登录窗口的实现,特点就是不用隐藏. 在入口处打开登陆: static void Main() { Application.EnableVisualStyles(); Application.Set ...

  4. &lbrack;CQOI2016&rsqb;伪光滑数

    题目描述 若一个大于1的整数M的质因数分解有k项,其最大的质因子为Ak,并且满足Ak^K<=N,Ak<128,我们就称整数M为N-伪 光滑数.现在给出N,求所有整数中,第K大的N-伪光滑数 ...

  5. es6 模板字符串

    模板字符串 提供构造字符串的语法糖,在 Prel/python 等语言中也都有类似特性. 1.反引号模板,可以换行 2.反引号模板,可以嵌套 用+``来嵌套 好处:语法更加简洁 var name=&q ...

  6. linux安装jdk8

    1.文件准备 jdk-8u201-linux-x64.tar.gz 下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8- ...

  7. &lbrack;PHP&rsqb; 看博客学习插入排序

    定义数组长度变量$len,使用count()函数,参数:数组 for循环数组,条件:从第二个开始,遍历数组,循环内 定义临时变量$temp,赋值当前元素 for循环数组,条件:遍历当前元素前面的所有元 ...

  8. Python 中函数的 收集参数 机制

    定义函数的时候,在参数前加了一个 * 号,函数可以接收零个或多个值作为参数.返回结果是一个元组. 传递零个参数时函数并不报错,而是返回一个空元组.但以上这种方法也有局限性,它不能收集关键字参数. 对关 ...

  9. HDU 2895 贪心 还是 大水题

    DESCRIPTION:大意是给你两个字符串.编辑距离只有add和delete会产生.所以.编辑距离最短一定是两个字符串的长度差.然后...呵呵呵呵.... 猜题意就可以了...但是...我觉得这个题 ...

  10. openstack kilo部署-基础环境

    公司也想搞个私有云玩玩,于是展开了一系列的调研,部署测试,openstack 有几个版本真是坑爹!!,如果喜欢被虐有兄弟,你就试试 openstack 的 juno , icehouse等版本,用不了 ...