項目實訓(二) 加載圓形圖(從源碼看自定義圖形轉換)

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):



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章