Custom BitmapTransformation of Kotlin's Glide

introduction


In the previous article , RecyclerView has been used to reuse controls to reduce performance and memory consumption. In this article, the display of the interface will be further optimized.

The image loading framework used in my project is Glide. Many people on the Internet are discussing the advantages. Here is why I choose Glide instead of Picasso, Fresco, etc.

1. The image loading request is related to the life cycle of the related Context,
which is a great advantage for this project and can reduce unnecessary performance consumption. Since the main interface structure of the project is composed of fragments, and each fragment needs to load a large number of pictures, when the fragment is switched, the life cycle change will trigger Glide to automatically suspend and resume the request, thereby saving traffic and memory, and preventing Memory leak.

2. The display effect after the image is loaded. I believe that many people who know Glide have seen the cool animation effect that gradually appears when Glide loads the image, which is mainly reflected in the user's senses.

The main reason is the above two points. Since Glide has a memory cache and disk cache strategy by default, you can use the default if it is not required.

Having said so much, this article mainly talks about "image processing", how to customize BitmapTransformation

text


Take a look at the comparison chart

other people's interface

my interface

Does it give people a blunt feeling? The pictures are angular and not very smooth. Fortunately, the official solution BitmapTransformation is given.

BitmapTransformation is an abstract class, the methods to be implemented are as follows

//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
    }

}

The process is not smooth

This is the process diagram

This is the final image

Did you find the problem with the same image? The image in the process diagram is cropped. . . . .

Since I specified the width and height of the ImageView during the layout, it will be cropped with the coordinates of the upper left corner when loading the large image, and it will be displayed normally when the width and height of the ImageView is changed to 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
    }
}

Of course, all image loading must be packaged together, so as not to change the image loading frame later

/**
 * 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)
        }

    }

}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325995515&siteId=291194637