前言
经常玩B站的同学应该都知道,认证后的用户的头像右下角会有一个小闪电的图标,有的是黄色的、有的是蓝色的。我想到 阳光沙滩 有 VIP 用户,我们也可以对用户群体进行区分,所以咱也整一个吧。
效果图
思路分析
思路1
我们可以使用组合控件的方式来实现这个效果,具体结构如下图所示:
- 优点
实现起来比较简单。
- 缺点
View 嵌套,且 View 个数较多。
思路2
除此之外,我们还可以通过自定义 ImageView
来实现。
首先 ImageView 的 setImageDrawable 方法设置头像图片,然后通过设置 ImageView 的 foreground 属性来实现添加右下角小图标的效果。
- 优点
只有一个 View ,不存在 View 的嵌套,性能相对较高;
- 缺点
实现较为复杂,需要具备自定义 View 的能力;
源码实现
代码比较简单,前面也讲了思路,关键点也在代码中加了注释。
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.ContextCompat
import androidx.core.graphics.scaleMatrix
import cn.cqautotest.sunnybeach.R
import cn.cqautotest.sunnybeach.http.glide.GlideApp
import cn.cqautotest.sunnybeach.util.dp
import com.blankj.utilcode.util.ImageUtils
/**
* author : A Lonely Cat
* github : https://github.com/anjiemo/SunnyBeach
* time : 2022/03/31
* desc : 头像装饰控件
*/
class AvatarDecorView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {
// 默认头像 drawable
private val defAvatarDrawable = ContextCompat.getDrawable(context, R.mipmap.ic_default_avatar)
// 边框 drawable
private val decorDrawable = GradientDrawable().apply {
shape = GradientDrawable.OVAL
setStroke(1.dp, ContextCompat.getColor(context, R.color.pink))
}
// 前景徽章图标的画笔
private val badgePaint = Paint(Paint.ANTI_ALIAS_FLAG)
// 小徽章 bitmap
private val badgeBitmap = ImageUtils.getBitmap(R.drawable.ic_flash)
// 缩放因子
private val scaleFactor = 0.22f
// 缩放矩阵
private val scaleMatrix = scaleMatrix(scaleFactor, scaleFactor)
// 是否为 VIP
var isVip: Boolean = false
init {
// 如果 xml 里没有设置资源图片,则设置默认的头像 drawable
if (drawable == null) setImageDrawable(defAvatarDrawable)
}
/**
* 加载头像(剪裁成圆形)
* 参数:
* 1、是否为 VIP
* 2、资源
* 3、边框的自定义配置
*/
fun loadAvatar(vip: Boolean = false, resource: Any?, block: GradientDrawable.() -> Unit = {}) {
isVip = vip
block.invoke(decorDrawable)
GlideApp.with(this)
.load(resource)
.placeholder(R.mipmap.ic_default_avatar)
.error(R.mipmap.ic_default_avatar)
.circleCrop()
.into(this)
}
/**
* 使用 Glide 加载 ImageView 图片时会调用此方法,我们可以在这里对设置的 drawable 资源进行修饰。
*/
override fun setImageDrawable(drawable: Drawable?) {
val decorDrawable = if (isVip && drawable != null) {
// 如果是 VIP 且 drawable 资源不为空,则添加 decorDrawable
LayerDrawable(arrayOf(drawable, decorDrawable))
} else {
// 如果设置的头像 drawable 为空,则设置默认头像 drawable
drawable ?: defAvatarDrawable
}
super.setImageDrawable(decorDrawable)
}
/**
* 绘制前景徽章图标
*/
override fun onDrawForeground(canvas: Canvas?) {
super.onDrawForeground(canvas)
canvas ?: return
if (isVip) {
// Timber.d("onDrawForeground:===> width is $width measuredWidth is $measuredWidth")
val dx = width - badgeBitmap.width * scaleFactor
val dy = height - badgeBitmap.height * scaleFactor
// 画布默认是在左上角,需要先调整画布的位置
canvas.translate(dx, dy)
// 绘制小徽章
canvas.drawBitmap(badgeBitmap, scaleMatrix, badgePaint)
}
}
}
结语
我写的 阳光沙滩APP项目 中也有使用到此功能,感兴趣的同学可以 clone 下来看看。如果只是想体验一下APP的话,请点击下载APP体验 (密码:5qlt)。
本文由
A lonely cat
原创发布于
阳光沙滩
,未经作者授权,禁止转载