天天看點

ImageLoader中自定義Displayer來展示任意圓角

ImageLoader自帶圓角圖檔的RoundedBitmapDisplayer,但這個displayer展示的效果是4個角都是圓角,而我們有時候隻需要其中的上面或下面2個角是圓角,本篇就是講這個方法的。

package com.uil;

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;

import com.nostra13.universalimageloader.core.assist.LoadedFrom;
import com.nostra13.universalimageloader.core.display.BitmapDisplayer;
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;

/**
 * Created by zhu.jiangtao on 2017/11/30.
 */

public class CornorBitmapDisplayer implements BitmapDisplayer {
    private int mTopLeftRadius;
    private int mTopRightRadius;
    private int mBottomRightRadius;
    private int mBottomLeftRadius;
    private int mMarginPixels;

    public CornorBitmapDisplayer(int topLeftRadius, int topRightRadius, int bottomRightRadius, int bottomLeftRadius) {
        this(topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius, );
    }

    public CornorBitmapDisplayer(int topLeftRadius, int topRightRadius, int bottomRightRadius, int bottomLeftRadius, int marginPixels) {
        this.mTopLeftRadius = topLeftRadius;
        this.mTopRightRadius = topRightRadius;
        this.mBottomRightRadius = bottomRightRadius;
        this.mBottomLeftRadius = bottomLeftRadius;
        this.mMarginPixels = marginPixels;
    }

    public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
        if(!(imageAware instanceof ImageViewAware)) {
            throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
        } else {
            imageAware.setImageDrawable(new CornorBitmapDisplayer.CornerDrawable(bitmap, this.mTopLeftRadius, this.mTopRightRadius, this.mBottomRightRadius, this.mBottomLeftRadius, this.mMarginPixels));
        }
    }

    protected static class CornerDrawable extends Drawable {
        private int mTopLeftRadius;
        private int mTopRightRadius;
        private int mBottomRightRadius;
        private int mBottomLeftRadius;
        private int mMargin;
        private final RectF mRect = new RectF();
        private final BitmapShader bitmapShader;
        private final Paint paint;
        private final RectF mBmpRect;

        public CornerDrawable(Bitmap bitmap, int topLeftRadius, int topRightRadius, int bottomRightRadius, int bottomLeftRadius, int marginPixels) {
            this.mTopLeftRadius = topLeftRadius;
            this.mTopRightRadius = topRightRadius;
            this.mBottomRightRadius = bottomRightRadius;
            this.mBottomLeftRadius = bottomLeftRadius;
            this.mMargin = marginPixels;
            this.bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            this.mBmpRect = new RectF((float)this.mMargin, (float)this.mMargin, (float)(bitmap.getWidth() - this.mMargin), (float)(bitmap.getHeight() - this.mMargin));
            this.paint = new Paint();
            this.paint.setAntiAlias(true);
            this.paint.setShader(this.bitmapShader);
        }

        protected void onBoundsChange(Rect bounds) {
            super.onBoundsChange(bounds);
            this.mRect.set((float)this.mMargin, (float)this.mMargin, (float)(bounds.width() - this.mMargin), (float)(bounds.height() - this.mMargin));
            Matrix mResizeMatrix = new Matrix();
            mResizeMatrix.setRectToRect(this.mBmpRect, this.mRect, Matrix.ScaleToFit.FILL);
            this.bitmapShader.setLocalMatrix(mResizeMatrix);
        }

        public void draw(Canvas canvas) {
            float[] radii = new float[]{(float)this.mTopLeftRadius, (float)this.mTopLeftRadius, (float)this.mTopRightRadius, (float)this.mTopRightRadius, (float)this.mBottomRightRadius, (float)this.mBottomRightRadius, (float)this.mBottomLeftRadius, (float)this.mBottomLeftRadius};
            Path path = new Path();
            path.addRoundRect(this.mRect, radii, Path.Direction.CW);
            canvas.drawPath(path, this.paint);
        }

        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }

        public void setAlpha(int alpha) {
            this.paint.setAlpha(alpha);
        }

        public void setColorFilter(ColorFilter cf) {
            this.paint.setColorFilter(cf);
        }
    }
}
           

絕大部分代碼都和RoundedBitmapDisplayer是一樣的,隻是onDraw中的利用path繪制圓角矩形的方法有點差別而已。

我們把這段代碼單獨拿出來看:

public void draw(Canvas canvas) {
            float[] radii = new float[]{(float)this.mTopLeftRadius, (float)this.mTopLeftRadius, (float)this.mTopRightRadius, (float)this.mTopRightRadius, (float)this.mBottomRightRadius, (float)this.mBottomRightRadius, (float)this.mBottomLeftRadius, (float)this.mBottomLeftRadius};
            Path path = new Path();
            path.addRoundRect(this.mRect, radii, Path.Direction.CW);
            canvas.drawPath(path, this.paint);
        }
           

主要調用的是 Path的addRoundRect(RectF rect, float[] radii, Direction dir)方法。radii中的值分别表示 左上、右上、左下和右下圓角的X,Y值。

而RoundedBitmapDisplayer中的onDraw方法卻是4個角都是圓角:

public void draw(Canvas canvas) {
            canvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);
        }
           

調用的Path的 drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) 即将rect的四個角都畫為圓角。

用的方法也很簡單,

//顯示圖檔的配置
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.drawable.ic_stub)
                .showImageOnFail(R.drawable.ic_error)
                .showImageForEmptyUri(R.drawable.ic_empty)
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .displayer(new CornorBitmapDisplayer(, , , ))//左上、和右上為圓角
                .build();

        ImageLoader.getInstance().displayImage(url, imgview, options, null);
           

效果如下:

ImageLoader中自定義Displayer來展示任意圓角

注意:顯示圖檔的ImageView需要設定具體的大小而不能是wrap_content