android 头像球_Android自定义View实现圆形头像效果
在我们的APP中通常会遇到,展示圆形头像的需求,一般通过Glide就能实现,但是让我们做一个圆形头像,如果让我们自定义实现这种效果,该怎样做呢?
好,接下来本文通过三种方式来实现这种效果!
注意:这是一个练手的Demo
1.通过本文可以学到的知识点canvas.clipPath API的使用
Xfermode的使用
Paint的Xfermode和ShaderAPI
Matrix的平移和Canvans的平移(源码中,为了在一个View同时展示三种效果,所以对Canvas坐标进行了平移)
总结三种实现方式的优缺点
2.通过自定义View制作圆形头像
通过三种方式来实现这种效果,是哪三种方式呢?通过canvas.clipPath()
通过paint.xfermode = porterDuffXfermode
通过paint.shader = bitmapShader
3.第一种实现方式
利用 canvas的 clip方法
private val AVATAR_SIZE = 240.dp //图片的大小private val RADIUS = AVATAR_SIZE / 2 //裁剪圆形的半径
class CircleAvatarView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint()
private var avatar = getAvatar(R.drawable.my_avatar, AVATAR_SIZE.toInt())//图片的bitmap private val circlePath = Path()//圆形的路径
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
/*** 在圆心 x:View宽度的一半 y:View高度的一半 半径为图片尺寸的一半 的位置上画圆*/
circlePath.addCircle(width / 2f, height / 2f, RADIUS, Path.Direction.CW)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//ktx的扩展方法,会自动保存恢复Canvas canvas.withSave {
//重置画笔 paint.reset()
//利用Canvas来裁切去要画的范围,也就是那个圆形 canvas.clipPath(circlePath)
//在裁切后画上声明的Bitmap canvas.drawBitmap(avatar, width / 2 - RADIUS, height / 2 - RADIUS, paint)
}
}
}
解释一下代码,当然看代码的注释也是一样的定义包级别的图片的宽度为240dp和圆形的半径
获取一个要展示的图片的Bitmap
声明一个要裁剪的圆形的Path
onSizeChanged方法中添加一个圆形
利用Canvas来裁切去要画的范围,也就是那个圆形
在裁切后画上声明的Bitmap
以上就是绘制圆形头像的第一种方法,主要使用的是canvas.clipPath(circlePath)方法,注意Canvas的保存和恢复
4.第二种实现方式
通过paint.xfermode = porterDuffXfermode
private val AVATAR_SIZE = 240.dp //图片的大小private val RADIUS = AVATAR_SIZE / 2 //裁剪圆形的半径
class CircleAvatarView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint()
private var avatar = getAvatar(R.drawable.my_avatar, AVATAR_SIZE.toInt())//图片的bitmap private val circlePath = Path()//圆形的路径 private val bounds = RectF()//离屏缓冲的 bounds private val porterDuffXfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
/*** 在圆心 x:View宽度的一半 y:View高度的一半 半径为图片尺寸的一半 的位置上画圆*/
circlePath.addCircle(width / 2f, height / 2f, RADIUS, Path.Direction.CW)
/*** 设置离屏缓冲的 bounds最好不要太大,影响性能*/
bounds.set(width / 2f - RADIUS, height / 2f - RADIUS,
width / 2f + RADIUS, height / 2f + RADIUS)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//开启离屏缓冲 val count = canvas.saveLayer(bounds, null)
paint.reset()
canvas.drawPath(circlePath, paint)
//设置paint的 xfermode 为PorterDuff.Mode.SRC_IN paint.xfermode = porterDuffXfermode
//以当前的Paint来画Bitmap canvas.drawBitmap(avatar, width / 2 - RADIUS, height / 2 - RADIUS, paint)
//清空paint 的 xfermode paint.xfermode = null
//把离屏缓冲的内容,绘制到View上去 canvas.restoreToCount(count)
}
}
解释一下代码,当然看代码的注释也是一样的在onSizeChanged方法中设置离屏缓冲的范围,是圆形头像的外切矩形的范围
onDraw方法中开启离屏缓冲
Canvas先画了一个圆形(相当于PorterDuff.Mode中的Destination image)
设置paint的 xfermode 为PorterDuff.Mode.SRC_IN
以当前的Paint来画Bitmap(注意此时相当于PorterDuff.Mode中的Source image),因为我们选择的模式为PorterDuff.Mode.SRC_IN所以就画出我们想要的效果
把离屏缓冲的内容,绘制到View上去
注意:一定要开启离屏缓冲,不然结果可能不是你所预期的,离屏缓冲相当于拿出一块透明的View来绘制,Canvas要绘制的图形
5.第三种实现方式
通过paint.shader = bitmapShader
private val AVATAR_SIZE = 240.dp //图片的大小private val RADIUS = AVATAR_SIZE / 2 //裁剪圆形的半径
class CircleAvatarView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint()
private var avatar = getAvatar(R.drawable.my_avatar, AVATAR_SIZE.toInt())//图片的bitmap private val circlePath = Path()//圆形的路径 private val bitmapShader = BitmapShader(avatar, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
/*** 在圆心 x:View宽度的一半 y:View高度的一半 半径为图片尺寸的一半 的位置上画圆*/
circlePath.addCircle(width / 2f, height / 2f, RADIUS, Path.Direction.CW)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.reset()
//给paint设置Shader paint.shader = bitmapShader
//以Shader的形式来画圆形 canvas.drawPath(circlePath, paint)
}
}
解释一下代码,当然看代码的注释也是一样的
这种方式就比较简单了声明一个BitmapShader,把头像的bitmap填入BitmapShader的构造中,并填入参数Shader.TileMode的值,这个具体看这篇文章对Paint做了详细解释
在onDraw方法中给paint设置Shader
以Shader的形式来画圆形,结果就是一个圆角头像了
6.总结
总结一下三种方式的优缺点
1.canvas.clipPath():
利用 canvas的 clip方法
没有抗锯齿效果,会有毛边,因为是精确的切像素点
2.paint.xfermode = porterDuffXfermode
利用 paint的 xfermode 方法
有抗锯齿效果,没有毛边,效果好,做了抗锯齿的处理,填充和周边类似的半透明色等
3.paint.shader = bitmapShader
利用 设置 paint 的 shader 方法
有抗锯齿效果,没有毛边,效果好
但是图片结果会受到Shader.TileMode影响,可能结果不是你所预期的
综上总结:最好使用paint.xfermode = porterDuffXfermode这种方式,因为我们需要的是一个显示完美的头像
此外还要注意使用离屏缓冲
7.源码地址
android 头像球_Android自定义View实现圆形头像效果相关推荐
- android 清空canvas部分内容_Android自定义View实现圆形头像效果
在我们的APP中通常会遇到,展示圆形头像的需求,一般通过Glide就能实现,但是让我们做一个圆形头像,如果让我们自定义实现这种效果,该怎样做呢? 好,接下来本文通过三种方式来实现这种效果! 注意:这是 ...
- android 头像球_Android一行代码实现圆形头像
效果图 在开发APP中,经常要实现圆形头像,那么该如何实现呢? 要裁剪吗,要重写draw函数吗?不用,只用一行代码就可以实现 Glide实现圆形图像 Glide.with(mContext) .loa ...
- android刷新时的圆形动画_Android自定义view渐变圆形动画
本文实例为大家分享了Android自定义view渐变圆形动画的具体代码,供大家参考,具体内容如下 直接上效果图 自定义属性 attrs.xml文件 创建一个类 ProgressRing继承自 view ...
- Android 自定义View实现圆形头像(适用于任意布局)
先看效果图: 先来说下我的思路:首先我需要在自定义View中动态获取头像id,那么就需要在attrs文件中,写一个关于该View类的自定义属性.这里仿照ImageView,取名为src,类型为refe ...
- Android自定义View之圆形头像
记录贴 现在制作圆形头像的第三方工具已经很多了,本帖只为记录自定义view学习过程. 1.主体代码部分 public class CirclePhotoView extends View {priva ...
- android 环绕布局,Android自定义View实现圆形环绕效果
之前项目中需要实现一个四周环绕中心圆形头像的效果,感觉还是自定义比较方便,于是就自己封装了一个控件去实现.先贴张图显示最终效果. 首先自定义一个View继承自LinearLayout,通过动态添加ch ...
- 自定义View,圆形头像
1. 效果图 2. xml中 <com.etoury.etoury.ui.view.CircleImgandroid:id="@+id/user_info_head_img" ...
- android java 圆角_Android自定义View实现带4圆角或者2圆角的效果
1 问题 实现任意view经过自定义带4圆角或者2圆角的效果 2 原理 1) 实现view 4圆角 我们只需要把左边的图嵌入到右边里面去,最终显示左边的图就行. 2) 实现view上2圆角 我们只需要 ...
- android 立体 流量球,Android自定义View——实现水波纹效果类似剩余流量球
Android自定义View--实现水波纹效果类似剩余流量球 三个点 pre ber block span 初始化 move 理解最近突然手痒就想搞个贝塞尔曲线做个水波纹效 ...
- android view 渐变动画,Android自定义view渐变圆形动画
本文实例为大家分享了Android自定义view渐变圆形动画的具体代码,供大家参考,具体内容如下 直接上效果图 自定义属性 attrs.xml文件 创建一个类 ProgressRing继承自 view ...
最新文章
- 如何在您HTML中嵌入视频和音频
- heartbeat+drbd+mysql:实现最廉价的高可用组合
- 会计职业道德教育的途径
- python matplotlib.pyplot.xticks() yticks() (设置x或y轴对应显示的标签)
- MySQL及其分支或衍生版
- Django 用 uploadify 实现图片批量上传
- VS2005快捷键大全(转)
- 《Java8实战》笔记(09):默认方法
- 二.Windows I/O模型之异步选择(WSAAsyncSelect)模型
- 使用gdaldem生成山体阴影——thematicmapping.org译文(二)
- 去除程序名称 去除程序属性详细信息中的程序名称 创建时间等信息
- 巧用“搜索”解决自学编程遇到的难题
- unity3d ppsspp模拟器中的post processing shader在unity中使用
- PYTHON之计算机语言基础知识 —— 字符编码
- 互联网大病公益众筹项目文本分析
- 基于android的电子词典设计_基于安卓Android的电子词典的设计与实现
- java wav 转 mp3_java,wavToMP3格式转换
- 解决 Elasticsearch 查询时 Fielddata is disabled on text fields by default 错误
- 新浪短网址生成java_新浪短网址(T.cn)/腾讯短链接(Url.cn)在线生成以及API接口申请的教程...
- Python系统学习流程图,教你一步步学习python