1. 程式人生 > >Android自定義圓角矩形ImageView,支援Glide載入圖片及顏色填充

Android自定義圓角矩形ImageView,支援Glide載入圖片及顏色填充

前言:

 之前用到圓角的情況大都是自定義一個shape背景drawable及用到v7包下的CardView包裹View實現圓角矩形效果,還有就是在使用者圓形頭像的時候需要使用到圓角矩形(圓形可以看做是特殊的圓角矩形),諸如Button,Editext,TextView的圓角矩形顏色背景可以用shape實現,但是ImageView Res圓角還沒用到過,它就不能簡單地設定一個圓角矩形shape作為背景了。這篇文章將介紹如何自定義一個ImageView實現image圓角矩形的效果及加上Glide和顏色填充的支援。效果如下:

這裡寫圖片描述

  1. 第一張圖片為用Glide載入的遠端圖片;
  2. 第二張為本地圖片(drawable);
  3. 第三張則為顏色填充。

程式碼編寫

1. 繼承AppCompatImageView,初始化

google推薦繼承AppCompatImageView實現自定義ImageView實現更好地相容。

/**
* 預設的圓角大小,單位為dp
 */
private static final float DEFAULT_CORNER = 10;
private Paint mPaint;
private int mCorner;

public RoundRectImageView(Context context) {
    this(context,null);
}

public RoundRectImageView
(Context context, AttributeSet attrs) { this(context, attrs,0); } public RoundRectImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mPaint = new Paint(); TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.RoundRectImageView); mCorner = (int
) typedArray.getDimension(R.styleable.RoundRectImageView_corner, dp2px(context, DEFAULT_CORNER)); typedArray.recycle(); }

這裡自定義了一個屬性corner:

<declare-styleable name="RoundRectImageView">
    <attr name="corner" format="dimension"></attr>
</declare-styleable>

2. 重寫onDraw(),裁剪圖片

/**
 * 繪製圓角矩形圖片
 */
@Override
protected void onDraw(Canvas canvas) {
    Drawable drawable = getDrawable();
    if ( drawable != null ) {
        Bitmap bitmap = null;
        // Drawable轉Bitmap
        if(drawable instanceof GlideBitmapDrawable) {
            bitmap = ((GlideBitmapDrawable)drawable).getBitmap();
        } else if(drawable instanceof ColorDrawable){
            bitmap = Bitmap.createBitmap(getWidth(),getHeight(),
                    Config.ARGB_8888);
            bitmap.eraseColor(((ColorDrawable) drawable).getColor());//填充顏色
        }else{
            bitmap = ((BitmapDrawable)drawable).getBitmap();
        }
        Bitmap roundBitmap = getRoundBitmap(bitmap, mCorner);
        final Rect rectSrc = new Rect(0, 0, roundBitmap.getWidth(), roundBitmap.getHeight());
        final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
        // 重置畫筆,不然會留下黑色區域
        mPaint.reset();
        canvas.drawBitmap(roundBitmap, rectSrc, rectDest, mPaint);
    } else {
        super.onDraw(canvas);
    }
}

其中的原理是先通過Drawable拿到Bitmap,對Bitmap進行裁剪,然後重繪Bitmap實現圓角矩形的效果。其中裁剪方法為:

/**
 * 裁剪圖片
 * @param bitmap
 * @param corner
 * @return Bitmap
 */
private Bitmap getRoundBitmap(Bitmap bitmap, int corner) {
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
            bitmap.getHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(output);
    final Rect rect = new Rect(getPaddingLeft(), getPaddingTop(), bitmap.getWidth()-getPaddingRight(), bitmap.getHeight()-getPaddingBottom());
    final RectF rectF = new RectF(rect);
    mPaint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    mPaint.setColor(Color.WHITE);
    canvas.drawRoundRect(rectF, corner, corner, mPaint);
    // 設定影象混合模式為SRC_IN,裁剪出我們的圓角Bitmap
    mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, mPaint);
    return output;
}

其中裁剪原理是通過兩個影象進行混合,這裡為SRC_IN模式,即可裁剪出我們需要的圓角矩形影象。

完整程式碼如下:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;

import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;


/**
 * 自定義圓角矩形ImageView
 * Created by LT on 2018/5/13.
 */
public class RoundRectImageView extends AppCompatImageView {

    /**
     * 預設的圓角大小,單位為dp
     */
    private static final float DEFAULT_CORNER = 10;
    private Paint mPaint;
    private int mCorner;

    public RoundRectImageView(Context context) {
        this(context,null);
    }

    public RoundRectImageView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public RoundRectImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mPaint = new Paint();
        TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.RoundRectImageView);
        mCorner = (int) typedArray.getDimension(R.styleable.RoundRectImageView_corner, dp2px(context, DEFAULT_CORNER));
        typedArray.recycle();
    }

    /**
     * 繪製圓角矩形圖片
     */
    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if ( drawable != null ) {
            Bitmap bitmap = null;
            // Drawable轉Bitmap
            if(drawable instanceof GlideBitmapDrawable) {
                bitmap = ((GlideBitmapDrawable)drawable).getBitmap();
            } else if(drawable instanceof ColorDrawable){
                bitmap = Bitmap.createBitmap(getWidth(),getHeight(),
                        Config.ARGB_8888);
                bitmap.eraseColor(((ColorDrawable) drawable).getColor());//填充顏色
            }else{
                bitmap = ((BitmapDrawable)drawable).getBitmap();
            }
            Bitmap roundBitmap = getRoundBitmap(bitmap, mCorner);
            final Rect rectSrc = new Rect(0, 0, roundBitmap.getWidth(), roundBitmap.getHeight());
            final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
            // 重置畫筆,不然會留下黑色區域
            mPaint.reset();
            canvas.drawBitmap(roundBitmap, rectSrc, rectDest, mPaint);
        } else {
            super.onDraw(canvas);
        }
    }

    /**
     * 裁剪圖片
     * @param bitmap
     * @param corner
     * @return Bitmap
     */
    private Bitmap getRoundBitmap(Bitmap bitmap, int corner) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final Rect rect = new Rect(getPaddingLeft(), getPaddingTop(), bitmap.getWidth()-getPaddingRight(), bitmap.getHeight()-getPaddingBottom());
        final RectF rectF = new RectF(rect);
        mPaint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        mPaint.setColor(Color.WHITE);
        canvas.drawRoundRect(rectF, corner, corner, mPaint);
        // 設定影象混合模式為SRC_IN,裁剪出我們的圓角Bitmap
        mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, mPaint);
        return output;
    }

    /**
     * dp轉 px.
     * @param value the value
     * @return the int
     */
    public static int dp2px(Context context, float value) {
        final float scale = context.getResources().getDisplayMetrics().densityDpi;
        return (int) (value * (scale / 160) + 0.5f);
    }
}