Android自定義圓角矩形ImageView,支援Glide載入圖片及顏色填充
阿新 • • 發佈:2019-02-06
前言:
之前用到圓角的情況大都是自定義一個shape背景drawable及用到v7包下的CardView包裹View實現圓角矩形效果,還有就是在使用者圓形頭像的時候需要使用到圓角矩形(圓形可以看做是特殊的圓角矩形),諸如Button,Editext,TextView的圓角矩形顏色背景可以用shape實現,但是ImageView Res圓角還沒用到過,它就不能簡單地設定一個圓角矩形shape作為背景了。這篇文章將介紹如何自定義一個ImageView實現image圓角矩形的效果及加上Glide和顏色填充的支援。效果如下:
- 第一張圖片為用Glide載入的遠端圖片;
- 第二張為本地圖片(drawable);
- 第三張則為顏色填充。
程式碼編寫
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);
}
}