Glide进阶(三) 加载圆形图(从源码看自定义图形转换)

Glide提供了多种默认的图形变换,如centerCrop(中心剪裁,同imageview的scaletype)等,可以通过在链式语法中加入transform(BitmapTransmation)来设置图片的变换。centerCrop实际上就是调用transform(new CenterCrop)。那先来看看这个centerCrop,直接继承自BitmapTransmation,核心方法就一个:
@SuppressWarnings("PMD.CompareObjectsWithEquals")
    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        final Bitmap toReuse = pool.get(outWidth, outHeight, toTransform.getConfig() != null
                ? toTransform.getConfig() : Bitmap.Config.ARGB_8888);
        Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight);
        if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
            toReuse.recycle();
        }
        return transformed;
    }

首先从Bitmap缓存池中取出一个目标宽高的可用的Bitmap(为了节省创建bitmap的开销,可能为null),然后交由TransformationUtils去完成图片变换,最后看这个bitmap能否回收。

看看这个执行变换的centerCrop:

public static Bitmap centerCrop(Bitmap recycled, Bitmap toCrop, int width, int height) {
        if (toCrop == null) {
            return null;
        } else if (toCrop.getWidth() == width && toCrop.getHeight() == height) {
            return toCrop;
        }
        // From ImageView/Bitmap.createScaledBitmap.
        final float scale;
        float dx = 0, dy = 0;
        Matrix m = new Matrix();
        if (toCrop.getWidth() * height > width * toCrop.getHeight()) {
            scale = (float) height / (float) toCrop.getHeight();
            dx = (width - toCrop.getWidth() * scale) * 0.5f;
        } else {
            scale = (float) width / (float) toCrop.getWidth();
            dy = (height - toCrop.getHeight() * scale) * 0.5f;
        }

        m.setScale(scale, scale);
        m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
        final Bitmap result;
        if (recycled != null) {
            result = recycled;
        } else {
            result = Bitmap.createBitmap(width, height, getSafeConfig(toCrop));
        }

        // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
        TransformationUtils.setAlpha(toCrop, result);

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint(PAINT_FLAGS);
        canvas.drawBitmap(toCrop, m, paint);
        return result;
    }

主要借助了Matrix设置缩放比和原图中可用部分的起始坐标,然后drawBitmap把原图画到结果bitmap的画布上。

首先判断原图和目标图的宽高比,如果原图比较胖则取result.height/beforeHeight作为缩放比,接下来再计算原图中起始点的坐标就可以了。


我们想要的效果是

照葫芦画瓢,我们也来自定义一个CircleTrans继承BitmapTransmation,getId方法随便返回一个字符串作为本转换的唯一标识即可,主要是对transform的实现:

@Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        //从缓存池中取出一个bitmap
        final Bitmap toReuse = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        final Bitmap result;
        if (toReuse != null) {
            result = toReuse;
        } else {
            result = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);
        }

        //目标圆的半径
        float radious=Math.min(outHeight,outWidth)/2;
        //计算缩放比和原图中的起始坐标
        final float scale;
        float dx=0,dy=0;
        if (toTransform.getWidth()>toTransform.getHeight()){
            scale=(float) outHeight/(float) toTransform.getHeight();
            dx=(toTransform.getWidth()-toTransform.getHeight())*0.5f;
        } else {
            scale=(float) outWidth/(float) toTransform.getWidth();
            dy=(toTransform.getHeight()-toTransform.getWidth())*0.5f;
        }
        Matrix matrix=new Matrix();
        matrix.setScale(scale,scale);
        matrix.postTranslate((int)(dx+0.5f),(int)(dy+0.5f));

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        //后面参数表示边缘复制
        BitmapShader shader = new BitmapShader(toTransform, BitmapShader.TileMode.CLAMP,
                BitmapShader.TileMode.CLAMP);
        shader.setLocalMatrix(matrix);
        paint.setShader(shader);
        paint.setAntiAlias(true);//抗锯齿
        //绘制,可以看到主要还是对画笔的设置,将原图按矩阵缩放并设置起始点后交给画笔。
        canvas.drawCircle(outWidth/2, outHeight/2, radious, paint);

        //判断能否回收Bitmap
        if (toReuse != null && !pool.put(toReuse)) {
            toReuse.recycle();
        }
        return result;
    }
写的应该是比较清楚了,借助矩阵将原图缩放并设置起始位置,这时他在我们眼里相当于一个边长为min(outWidth,outHeight)的正方形,然后交给画笔作为圆形画到目标bitmap的画布上就可以了。


使用:

Glide.with(this)
                .load(path)
                .transform(new CircleTrans(this))
                .into(iv);

效果很理想(宽match_parent,高200dp):



猜你喜欢

转载自blog.csdn.net/zhang___yong/article/details/80383505