Android 完美实现图片圆角和圆形(对实现进行分析)
本来想在网上找个圆角的例子看一看,不尽人意啊,基本都是官方的Demo的那张原理图,稍后会贴出。于是自己自定义了个View,实现图片的圆角以及圆形效果。效果图:
第一个是原图,第二个是圆形效果,第三第四设置了不同的圆角大小。
准备改变一个博客的风格,首先给大家讲一下原理,让大家明白了,然后再贴代码,不然可以直接看那么长的代码也比较痛苦,核心代码其实就那么几行:
核心代码分析:
/**
* 根据原图和变长绘制圆形图片
*
* @param source
* @param min
* @return
*/
private Bitmap createCircleImage(Bitmap source, int min)
{
final Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min, min, Config.ARGB_8888);
/**
* 产生一个同样大小的画布
*/
Canvas canvas = new Canvas(target);
/**
* 首先绘制圆形
*/
canvas.drawCircle(min / , min / , min / , paint);
/**
* 使用SRC_IN
*/
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
/**
* 绘制图片
*/
canvas.drawBitmap(source, , , paint);
return target;
}
其实主要靠:paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));这行代码,为什么呢,我给大家解释下,SRC_IN这种模式,两个绘制的效果叠加后取交集展现后图,怎么说呢,咱们第一个绘制的是个圆形,第二个绘制的是个Bitmap,于是交集为圆形,展现的是BItmap,就实现了圆形图片效果。圆角,其实就是先绘制圆角矩形,是不是很简单,以后别人再说实现圆角,你就把这一行代码给他就行了。
从Android的示例中,给大家证明一下:
下面有一张PorterDuff.Mode的16中效果图,咱们的只是其一:
源码咱们只关心谁先谁后绘制的:
canvas.translate(x, y);
canvas.drawBitmap(mDstB, , , paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, , , paint);
paint.setXfermode(null);
canvas.restoreToCount(sc);
可以看出先绘制的Dst,再绘制的Src,最后的展示是SrcIn那个图:显示的区域是二者交集,展示的是Src(后者)。和咱们前面结论一致。效果16种,大家可以自由组合展示不同的效果。
好了,原理和核心代码解释完成。下面开始写自定义View。
1、自定义属性:
<?xml version="1.0" encoding="utf-8"?>
<resources> <attr name="borderRadius" format="dimension" />
<attr name="type">
<enum name="circle" value="" />
<enum name="round" value="" />
</attr>
<attr name="src" format="reference"></attr> <declare-styleable name="CustomImageView">
<attr name="borderRadius" />
<attr name="type" />
<attr name="src" />
</declare-styleable> </resources>
2、构造中获取自定义的属性:
/**
* TYPE_CIRCLE / TYPE_ROUND
*/
private int type;
private static final int TYPE_CIRCLE = ;
private static final int TYPE_ROUND = ; /**
* 图片
*/
private Bitmap mSrc; /**
* 圆角的大小
*/
private int mRadius; /**
* 控件的宽度
*/
private int mWidth;
/**
* 控件的高度
*/
private int mHeight; public CustomImageView(Context context, AttributeSet attrs)
{
this(context, attrs, );
} public CustomImageView(Context context)
{
this(context, null);
} /**
* 初始化一些自定义的参数
*
* @param context
* @param attrs
* @param defStyle
*/
public CustomImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyle, ); int n = a.getIndexCount();
for (int i = ; i < n; i++)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.CustomImageView_src:
mSrc = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, ));
break;
case R.styleable.CustomImageView_type:
type = a.getInt(attr, );// 默认为Circle
break;
case R.styleable.CustomImageView_borderRadius:
mRadius= a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f,
getResources().getDisplayMetrics()));// 默认为10DP
break;
}
}
a.recycle();
}
3、onMeasure中获取控件宽高:
/**
* 计算控件的高度和宽度
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 设置宽度
*/
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec); if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
{
mWidth = specSize;
} else
{
// 由图片决定的宽
int desireByImg = getPaddingLeft() + getPaddingRight()
+ mSrc.getWidth();
if (specMode == MeasureSpec.AT_MOST)// wrap_content
{
mWidth = Math.min(desireByImg, specSize);
} else mWidth = desireByImg;
} /***
* 设置高度
*/ specMode = MeasureSpec.getMode(heightMeasureSpec);
specSize = MeasureSpec.getSize(heightMeasureSpec);
if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
{
mHeight = specSize;
} else
{
int desire = getPaddingTop() + getPaddingBottom()
+ mSrc.getHeight(); if (specMode == MeasureSpec.AT_MOST)// wrap_content
{
mHeight = Math.min(desire, specSize);
} else
mHeight = desire;
} setMeasuredDimension(mWidth, mHeight); }
4、根据Type绘制:
/**
* 绘制
*/
@Override
protected void onDraw(Canvas canvas)
{ switch (type)
{
// 如果是TYPE_CIRCLE绘制圆形
case TYPE_CIRCLE: int min = Math.min(mWidth, mHeight);
/**
* 长度如果不一致,按小的值进行压缩
*/
mSrc = Bitmap.createScaledBitmap(mSrc, min, min, false); canvas.drawBitmap(createCircleImage(mSrc, min), , , null);
break;
case TYPE_ROUND:
canvas.drawBitmap(createRoundConerImage(mSrc), , , null);
break; } } /**
* 根据原图和变长绘制圆形图片
*
* @param source
* @param min
* @return
*/
private Bitmap createCircleImage(Bitmap source, int min)
{
final Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min, min, Config.ARGB_8888);
/**
* 产生一个同样大小的画布
*/
Canvas canvas = new Canvas(target);
/**
* 首先绘制圆形
*/
canvas.drawCircle(min / , min / , min / , paint);
/**
* 使用SRC_IN,参考上面的说明
*/
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
/**
* 绘制图片
*/
canvas.drawBitmap(source, , , paint);
return target;
} /**
* 根据原图添加圆角
*
* @param source
* @return
*/
private Bitmap createRoundConerImage(Bitmap source)
{
final Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888);
Canvas canvas = new Canvas(target);
RectF rect = new RectF(, , source.getWidth(), source.getHeight());
canvas.drawRoundRect(rect, mRadius, mRadius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(source, , , paint);
return target;
}
好了,我就不解析代码了,自定义View这是第五篇了,,,,写得好恶心,,,,
各位赞一个或者留个言,算是对我的支持~
源码点击下载
=========================================简单修复了一下,在ScrollView以及AdapterView中的headview的显示异常的bug============
修复后代码下载:
源码点击下载
相关博文,同时也推荐使用:
Android BitmapShader 实战 实现圆形、圆角图片
Android 完美实现图片圆角和圆形(对实现进行分析)的更多相关文章
- android 加载图片圆角等功能的处理
以Glide为例: Glide.with(getContext()).load(item.getSoftLogo()).transform(this.glideRoundTransform).into ...
- [Android] 给图像加入相框、圆形圆角显示图片、图像合成知识
前一篇文章讲述了Android触屏setOnTouchListener实现突破缩放.移动.绘制和加入水印,继续我的"随手拍"项目完毕给图片加入相框.圆形圆角显示图片和图像合 ...
- Android Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果
Android Glide加载图片时转换为圆形.圆角.毛玻璃等图片效果 附录1简单介绍了Android开源的图片加载框架.在实际的开发中,虽然Glide解决了快速加载图片的问题,但还有一个问题悬 ...
- Android长方形图片生成正圆形,以及矩形图片生成圆角
一般要做正圆形图片,只能是正方形的基础上才能实现,否则就变成椭圆了,下面说说如何使长方形的图片生成正圆形图片 废话不多说,没图没真相,先上图吧: 原图: 变成正圆后: 下面上代码: public ...
- Glide的加载图片的帮助类,用来把图片圆角或者改成圆形图片
Glide虽然非常好用但是没找到把图片圆角的方法,所以百度了一个非常不错的加载类自己实现圆角图 感谢原文章作者:http://blog.csdn.net/weidongjian/article/det ...
- 使用Picasso实现图片圆角和图片圆形
作者很好的文章访问量缺很少也很难搜到(我这里插个眼以后用的到)作者:先知丨先觉 来源:CSDN 原文:https://blog.csdn.net/github_33304260/article/det ...
- Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等
仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...
- Picasso – Android系统的图片下载和缓存类库
Picasso – Android系统的图片下载和缓存类库 Picasso 是Square开源的一个用于Android系统下载和缓存图片的项目.该项目和其他一些下载图片项目的主要区别之一是:使用4.0 ...
- Android中实现ListView圆角效果[转]
本文演示如何Android中实现ListView圆角效果. 无论是网站,还是APP,人们都爱看一些新颖的视图效果.直角看多了,就想看看圆角,这几年刮起了一阵阵的圆角设计风:CSS新标准纳入圆角元素,特 ...
随机推荐
- extern "c"用法
在Windows驱动开发中,如果是使用C++开发的,那么必须在有些关键函数钱加extern c 的关键词,否则编译出来的函数,跟C语言编译的函数不同,导致驱动程序不能 被有效识别. 最关键的是Driv ...
- Network Attack
Network Attack Nicola regularly inspects the local networks for security issues. He uses a smart and ...
- The Most Wanted Letter
The Most Wanted Letter You are given a text, which contains different english letters and punctuatio ...
- jquery-ui datepicker使用
这是一款老外设计的日期控件 很多显示方式都是国外的 需要自己调整一下 closeText: "Done", prevText: "上一月", nextText: ...
- tcpdump详细用法
1.1 三种关键字 关于类型的关键字 第一种是关于类型的关键字,主要包括host,net,port, 例如 host 210.27.48.2,指明 210.27.48.2是一台主机,n ...
- log4net logfornet 配置和用法
较好的参考地址: http://in3040.blog.163.com/blog/static/116702443201091354028744/ http://dev.tot.name/dotnet ...
- 【转】UltraISO制作U盘启动盘安装Win7/9/10系统攻略
U盘安装好处就是不用使用笨拙的光盘,光盘还容易出现问题,无法读取的问题.U盘体积小,携带方便,随时都可以制作系统启动盘. U盘建议选择8G及以上大小的. 下面一步一步讲解如果制作U盘安装盘: 1.首先 ...
- Hdu5785-Interesting(回文串处理)
Problem Description Alice get a string S. She thinks palindrome string is interesting. Now she wanna ...
- HDOJ-1016 Prime Ring Problem(DFS)
http://acm.hdu.edu.cn/showproblem.php?pid=1016 题意:输入n,代表有一个包含n个节点的环,在环中的节点中填入1,2...n-1,n,要求填入的数与左边的数 ...
- sem_timedwait的用法
#include <semaphore.h> int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); Link ...