Android圆角图片最佳方案
关于“Android圆角图片”,网上可以搜索到大把代码示例。而这些示例千篇一律过于单一,而 且对内存性能没有进行较好分析 本文将总结网上流行的几种圆角图片方案,进行性能与内存的分析,并得出最佳方案。(PS:本人初出江湖,高手勿喷)。
基础脑补:
位图:256位对比32位,存储信息量大但是占用内存也大, 图像质量较高。
ARGB:A=Alpha, R=Red, G=Green,B=Blue
ARGB_8888:8888意味着它们都用8个位来显示,32位的位图。
ARGB_4444:逻辑同上,16位的位图。
RGB_565:逻辑同上,16位的位图。
ALPHA_8:用8个位来表示透明度,8位的位图。
圆角方案一: PortrDuffXfermode拷贝Bitmap
代码:[java] view plain copy
- publicstaticBitmapgetRoundedCornerBitmap(Bitmapbitmap,intpixels){
- Bitmapoutput=Bitmap.createBitmap(bitmap.getWidth(),bitmap
- .getHeight(),Config.ARGB_8888);
- Canvascanvas=newCanvas(output);
- finalintcolor=0xff424242;
- finalPaintpaint=newPaint();
- finalRectrect=newRect(0,0,bitmap.getWidth(),bitmap.getHeight());
- finalRectFrectF=newRectF(rect);
- finalfloatroundPx=pixels;//圆角
- paint.setAntiAlias(true);
- canvas.drawARGB(0,0,0,0);
- paint.setColor(color);
- canvas.drawRoundRect(rectF,roundPx,roundPx,paint);
- paint.setXfermode(newPorterDuffXfermode(Mode.SRC_IN));//Mode.SRC_IN用前面画的“圆角矩形”对bitmap进行裁剪。
- canvas.drawBitmap(bitmap,rect,rect,paint);
- returnoutput;
- }
大概思路:从内存中创建一张同样大小的位图output,并使用canvas技术对图片进行裁剪并绘制的output中。
疑点集合:为啥采用0xff424242?
优点:使用简单。
缺点:方法栈内存消耗大,在方法消耗多1倍原有的bitmap内存且性能低下,在图片较大时有OOM的可能。 不适应ImageView,无法与ImageView的scaleType很好的工作,尤其是图片较小的情况下,圆角效果将破坏整个图像的呈现。
圆角方案二:PortrDuffXfermodeImageView
覆盖ImageView的onDraw方法。 [java] view plain copy- @Override
- protectedvoidonDraw(Canvascanvas){
- DrawablemaiDrawable=getDrawable();
- floatmCornerRadius=6*getContext().getResources().getDisplayMetrics().density;//圆角半径
- if(maiDrawableinstanceofBitmapDrawable&&mCornerRadius>0){
- Paintpaint=((BitmapDrawable)maiDrawable).getPaint();
- finalintcolor=0xff000000;
- finalRectFrectF=newRectF(0,0,getWidth(),getHeight());
- intsaveCount=canvas.saveLayer(rectF,null,Canvas.MATRIX_SAVE_FLAG|Canvas.CLIP_SAVE_FLAG|Canvas.HAS_ALPHA_LAYER_SAVE_FLAG|Canvas.FULL_COLOR_LAYER_SAVE_FLAG
- |Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- paint.setAntiAlias(true);
- canvas.drawARGB(0,0,0,0);
- paint.setColor(color);
- canvas.drawRoundRect(rectF,mCornerRadius,mCornerRadius,paint);
- XfermodeoldMode=paint.getXfermode();
- paint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- super.onDraw(canvas);
- paint.setXfermode(oldMode);
- canvas.restoreToCount(saveCount);
- }else{
- super.onDraw(canvas);
- }
- }
大概思路:ImageView会将src图片最终转化位一个drawable,通过getDrawable()获取该drawable,并获取其画笔。通过saveLayer。我们可以创建一个新图层,并在上面绘制。 对画笔使用PorterDuffXfermode。从而将圆角效果绘制出来。
优点:与前者相比,能很好的兼容ImageView的scaleType。
缺点:运行速度较为缓慢,由于onDraw运行在ui线程,PorterDuffXfermode是采用SRC_IN的方式进行图像裁剪,这种裁剪方式的速度具体视图像大小质量而视,使用不当容易Anr。
(ps: 个人猜测,PorterDuffXfermode采用逐个字节处理的方式执行,想想如果图像越大,字节数量越多,那花费时间势必超过5秒。)
圆角方案三:使用Path进行圆角边缘化
继承ImageView增加以下方法。[java] view plain copy
- @TargetApi(11)
- privatevoidinit(){
- setLayerType(View.LAYER_TYPE_SOFTWARE,null);
- this.mMaskPaint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.CLEAR));
- }
- privatevoidgenerateMaskPath(intwidth,intheight){
- this.mMaskPath=newPath();
- this.mMaskPath.addRoundRect(newRectF(0.0F,0.0F,width,height),this.mCornerRadius,this.mCornerRadius,Path.Direction.CW);
- this.mMaskPath.setFillType(Path.FillType.INVERSE_WINDING);
- }
- @Override
- protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
- super.onSizeChanged(w,h,oldw,oldh);
- if((w!=oldw)||(h!=oldh))
- generateMaskPath(w,h);
- }
- protectedvoidonDraw(Canvascanvas){
- //保存当前layer的透明橡树到离屏缓冲区。并新创建一个透明度爲255的新layer
- intsaveCount=canvas.saveLayerAlpha(0.0F,0.0F,canvas.getWidth(),canvas.getHeight(),
- 255,Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
- super.onDraw(canvas);
- if(this.mMaskPath!=null){
- canvas.drawPath(this.mMaskPath,this.mMaskPaint);
- }
- canvas.restoreToCount(saveCount);
- }
大概思路:创建以“圆角矩形”为结构的Path,并利用Path.FillType.INVERSE_WINDING反选“圆角矩形区域”。从而达到圆角边缘化的效果。
优点:与前者相比,由于不需要对ImageView的图片进行字节操作,所以速度快许多,而且在动画表现上十分平滑。
缺点:暂无。
更多相关文章
- android学习——GridView实现主界面布局
- Android拼接合并图片生成长图
- android通过Base64往服务器上传图片和对象
- android中ImageView属性及其详解
- Android(安卓)SQlite数据库的使用(一)-一学就会android数据库
- 关于在Android(安卓)Studio中使用Assets目录下的资源的问题
- Android性能优化《Android开发艺术探索》笔记
- Android极致优化
- Android――Android(安卓)lint工具项目资源清理详解