自定义Glide的Transformation实现部分圆角的文章和代码在网上有很多,原本我也是随便在网上找一份Glide 加载部分圆角图片在项目中直接使用,但在使用过程居然遇到Bug,所以去查看了官方文档,发现自定义的Transformation忘掉了最关键的部分,即重写equals()/hashCode()两个函数,虽然在一般场景下可以正常使用,但在RecyclerView这种会加载大量图片的场景下,自定义的transform且未重写equals()/hashCode()会导致Bug。
(emmm,具体是什么Bug我忘了,大概是滑动卡顿?因为是很久之前遇到的问题,现在补的文章)
先来看看官方文档:
官方文章中注明equals()/hashCode()/updateDiskCacheKey()三个方法是必须被重写以使得磁盘和内存缓存正确地工作。不重写equals()/hashCode()磁盘缓存就可能无法正常工作,虽然可以通过编译,但使用时会引起内存泄露等问题。
最后附上修改后的RoundedCornersTransform,目前可以正常使用:
//Koltin版本
class RoundedCornersTransform(
context: Context?,
var radius: Float,
var leftTop: Boolean = true,
var rightTop: Boolean = true,
var leftBottom: Boolean = true,
var rightBottom: Boolean = true
) :
Transformation<Bitmap?> {
private val mBitmapPool: BitmapPool = Glide.get(context!!).bitmapPool
private val id = javaClass.name
private val idBytes = id.toByteArray(Charsets.UTF_8);
override fun transform(
context: Context,
resource: Resource<Bitmap?>,
outWidth: Int,
outHeight: Int
): Resource<Bitmap?> {
val source: Bitmap = resource.get()
var finalWidth: Int
var finalHeight: Int
//输出目标的宽高或高宽比例
var scale: Float
if (outWidth > outHeight) {
//如果 输出宽度 > 输出高度 求高宽比
scale = outHeight.toFloat() / outWidth.toFloat()
finalWidth = source.width
//固定原图宽度,求最终高度
finalHeight = (source.width.toFloat() * scale).toInt()
if (finalHeight > source.height) {
//如果 求出的最终高度 > 原图高度 求宽高比
scale = outWidth.toFloat() / outHeight.toFloat()
finalHeight = source.height
//固定原图高度,求最终宽度
finalWidth = (source.height.toFloat() * scale).toInt()
}
} else if (outWidth < outHeight) {
//如果 输出宽度 < 输出高度 求宽高比
scale = outWidth.toFloat() / outHeight.toFloat()
finalHeight = source.height
//固定原图高度,求最终宽度
finalWidth = (source.height.toFloat() * scale).toInt()
if (finalWidth > source.width) {
//如果 求出的最终宽度 > 原图宽度 求高宽比
scale = outHeight.toFloat() / outWidth.toFloat()
finalWidth = source.width
finalHeight = (source.width.toFloat() * scale).toInt()
}
} else {
//如果 输出宽度=输出高度
finalHeight = source.height
finalWidth = finalHeight
}
//修正圆角
radius *= finalHeight.toFloat() / outHeight.toFloat()
val outBitmap: Bitmap = mBitmapPool[finalWidth, finalHeight, Bitmap.Config.ARGB_8888]
val canvas = Canvas(outBitmap)
val paint = Paint()
//关联画笔绘制的原图bitmap
val shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
//计算中心位置,进行偏移
val width: Int = (source.width - finalWidth) / 2
val height: Int = (source.height - finalHeight) / 2
if (width != 0 || height != 0) {
val matrix = Matrix()
matrix.setTranslate((-width).toFloat(), (-height).toFloat())
shader.setLocalMatrix(matrix)
}
paint.shader = shader
paint.isAntiAlias = true
val rectF = RectF(0.0f, 0.0f, canvas.width.toFloat(), canvas.height.toFloat())
//先绘制圆角矩形
canvas.drawRoundRect(rectF, radius, radius, paint)
//左上角圆角
if (!leftTop) {
canvas.drawRect(0f, 0f, radius, radius, paint)
}
//右上角圆角
if (!rightTop) {
canvas.drawRect(canvas.width - radius, 0f, canvas.width.toFloat(), radius, paint)
}
//左下角圆角
if (!leftBottom) {
canvas.drawRect(0f, canvas.height - radius, radius, canvas.height.toFloat(), paint)
}
//右下角圆角
if (!rightBottom) {
canvas.drawRect(
canvas.width - radius,
canvas.height - radius,
canvas.width.toFloat(),
canvas.height.toFloat(),
paint
)
}
return BitmapResource.obtain(outBitmap, mBitmapPool)!!
}
/** must override */
override fun equals(other: Any?): Boolean {
return other is RoundedCornersTransform
}
/** must override */
override fun hashCode(): Int {
return id.hashCode()
}
/** must override */
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update(idBytes)
}
}
RoundedCornersTransform使用:
//默认裁剪四个圆角,不需要设置圆角,对应参数设为false
Glide.with(context)
.load(item.coverUrl)
.apply(
RequestOptions().transform(
CenterCrop(), RoundedCornersTransform(
context, 8f,
leftBottom = false,
rightBottom = false
)
)
)
.into(holder.getView(R.id.img_icon))