Kotlin之Glide的自定义BitmapTransformation

本文介绍如何使用Glide加载图片并自定义BitmapTransformation实现圆角及圆形图片效果,解决图片加载过程中可能出现的问题。

引言


上一篇中利用RecyclerView已经实现了将控件复用以达到减少性能和内存消耗的目的,这一篇中将进一步优化界面的显示。

我项目中采用的图片加载框架是Glide,优点什么的网上很多人都在讨论,这里说一下我为什么选用Glide而不是Picasso、Fresco等。

1、图片的加载请求和与之相关Context的生命周期是相关联的,
这一点对于此项目是有很大优势的,可以减少不必要的性能消耗。由于项目的界面主结构是由fragment组成的,且各fragment都要加载大量的图片,当fragment切换时生命周期变化会触发Glide自动的将请求进行暂停和恢复操作,从而节约流量和内存,并且防止内存泄露。

2、图片加载后的展示效果,相信很多知道Glide的人都有见过Glide加载图片时渐显的酷炫动画效果,这一点主要体现在用户的感官上。

主要原因是以上两点,由于Glide默认设置已经有了内存缓存和磁盘缓存策略,如果不是硬性需要可使用默认。

说了这么多本文主要讲的要来了“图片处理”,如何自定义BitmapTransformation

正文


先看看对比图

别人家的界面

我的界面

是不是给人一种生硬的感觉,图片都是有棱有角的不是很顺滑,还好官方给出了处理办法BitmapTransformation

BitmapTransformation是一个抽象类,需要实现的方法如下

//toTransform为源
protected abstract Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight);
/**
 * Created by mr.lin on 2018/1/14.
 * 圆角图片转换
 */
class GlideRoundTransform(context: Context, private var radius: Int) : BitmapTransformation(context) {

    override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap? {

        return roundCrop(pool, toTransform)

    }

    private fun roundCrop(pool: BitmapPool, source: Bitmap): Bitmap {
        var result = pool.get(source.width, source.height, Bitmap.Config.ARGB_8888)
        if (result == null) {
            result = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
        }
        //这时result只是一张指定了大小的空图,如果要求不高的话可以更改ARGB_8888以减少内存消耗
        val canvas = Canvas(result)
        val paint = Paint()
        paint.shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        paint.isAntiAlias = true
        val rectF = RectF(0f, 0f, source.width.toFloat(), source.height.toFloat())
        canvas.drawRoundRect(rectF, radius.toFloat(), radius.toFloat(), paint)
        //操作其实很简单就是画了一个圆角矩形
        return result
    }
    //用于标示BitmapTransformation,接口Transformation<T> 有解释用以标示唯一对象的key
    override fun getId(): String {
        return this.javaClass.name
    }

}

过程并不是一帆风顺的

这是过程图

这是最终图

同一张图片发现问题了吗?过程图中的图片被裁剪了。。。。。

由于我在布局的时候对ImageView的宽高进行了指明,导致加载大图的时候会以左上角坐标进行裁剪,当改变ImageView宽高为wrap_content时才显示正常。

/**
 * Created by mr.lin on 2018/1/15.
 * 圆形图片转换
 */
class GlideCircleTransform(context: Context?) : BitmapTransformation(context) {

    override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
        return circleCrop(pool, toTransform)
    }

    private fun circleCrop(pool: BitmapPool, source: Bitmap): Bitmap {

        val size = Math.min(source.width, source.height)
        val x = (source.width - size) / 2
        val y = (source.height - size) / 2

        val squared = Bitmap.createBitmap(source, x, y, size, size)

        var result = pool.get(size, size, Bitmap.Config.ARGB_8888)
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
        }

        val canvas = Canvas(result)
        val paint = Paint()
        paint.shader = BitmapShader(squared, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        paint.isAntiAlias = true
        val r = size / 2f
        canvas.drawCircle(r, r, r, paint)
        return result
    }

    override fun getId(): String {
        return this.javaClass.name
    }
}

当然所有的图片加载都要封装到一起,以免以后更换图片加载框架

/**
 * Created by mr.lin on 2018/1/14.
 * glide工具
 */
class GlideUtils {

    companion object {

        fun loadImage(context: Context, url: String, iv: ImageView) {
            Glide.with(context)
                    .load(url)
                    .into(iv)
        }

        fun loadRoundImage(context: Context, url: String, iv: ImageView, radius: Int) {
            Glide.with(context)
                    .load(url)
                    .transform(GlideRoundTransform(context, CommonUtils.dpTopx(radius.toFloat())))
                    .into(iv)
        }

        fun loadCircleImage(context: Context, url: String, iv: ImageView) {
            Glide.with(context)
                    .load(url)
                    .transform(GlideCircleTransform(context))
                    .into(iv)
        }

    }

}
<think> 我们正在回答用户关于在Android中使用Glide图片设置为圆形的问题。 根据之前提供的系统级指令,我们需要在回答中: 1. 使用行内数学表达式时用$...$ 2. 独立公式用$$...$$ 3. 使用中文回答 4. 生成相关问题 5. 引用的段落末尾添加引用标识 但是注意,当前问题是一个技术问题,不涉及数学公式,因此我们可能不需要使用LaTeX数学表达式。但我们仍需遵守其他规则。 另外,用户要求参考站内引用,但这里没有提供具体的引用内容,因此我们只能根据一般知识回答。 回答结构: 1. 直接回答问题,给出使用Glide设置圆形图片的方法。 2. 提供示例代码(使用代码块)。 3. 解释关键步骤(可选)。 4. 生成相关问题。 注意:在Android中,Glide本身不直接提供圆形图片变换,但可以通过集成一个圆形变换的类来实现,或者使用Glide的扩展库(如果有)。常见的做法是使用`BitmapTransformation`自定义变换,或者使用第三方提供的圆形变换。 然而,Glide v4开始,可以使用`CircleCrop`选项来轻松实现圆形裁剪。 因此,我们可以这样回答: </think> ### 在 Android 中使用 Glide 设置圆形图片的方法 在 Android 开发中,使用 Glide 设置圆形图片主要有两种方式: #### ▶ 方法一:使用内置的 `CircleCrop` 变换(推荐) ```kotlin Glide.with(context) .load(imageUrl) // 图片资源(URL/资源ID/文件等) .apply(RequestOptions.bitmapTransform(CircleCrop())) // 关键变换 .into(imageView) ``` #### ▶ 方法二:自定义圆形变换 如需特殊边框等效果,可自定义 `BitmapTransformation`: ```kotlin class CircleTransform : BitmapTransformation() { override fun transform(pool: BitmapPool, source: Bitmap, outWidth: Int, outHeight: Int): Bitmap { val size = min(source.width, source.height) val x = (source.width - size) / 2 val y = (source.height - size) / 2 val squared = Bitmap.createBitmap(source, x, y, size, size) val result = pool.get(size, size, Bitmap.Config.ARGB_8888) val canvas = Canvas(result) val paint = Paint().apply { shader = BitmapShader(squared, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) isAntiAlias = true } canvas.drawCircle(size / 2f, size / 2f, size / 2f, paint) squared.recycle() return result } override fun updateDiskCacheKey(messageDigest: MessageDigest) { messageDigest.update("circle".toByteArray()) } } // 使用方式 Glide.with(context) .load(imageUrl) .transform(CircleTransform()) .into(imageView) ``` #### 注意事项 1. 添加 Glide 依赖(当前最新版): ```gradle implementation 'com.github.bumptech.glide:glide:4.16.0' kapt 'com.github.bumptech.glide:compiler:4.16.0' // 如需注解处理 ``` 2. `CircleCrop()` 需 Glide v4.0+ 支持 3. 自定义变换建议复用对象避免重复创建[^1] 📌 提示:对于圆角矩形效果,可使用 `RoundedCorners(radius)` 变换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值