前言
之前我們已經提到過,我們可以使用兩種方式來實現圓角圖片的效果。一種是使用Xfermode,另一種是BitmapShader來實現。下面我將介紹BitmapShader用法。
使用BitmapShader的方式實現
1.自定義屬性在attrs.xml文件中
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="borderRadius" format="dimension" />
<attr name="type">
<enum name="circle" value="0"/>
<enum name="round" value="1"/>
</attr>
<declare-styleable name="RoundImageView">
<attr name="borderRadius"/>
<attr name="type"/>
</declare-styleable>
</resources>
2.自定義ImageView
public class RoundImageView extends ImageView {
private int type;
private static final int TYPE_CIRCLE = 0;
private static final int TYPE_ROUND = 1;
//圓形半徑大小
private int mRadius;
//圓角矩形半徑大小
private int mBorderRadius;
//圓角默認值
private static final int BODER_RADIUS_DEFAULT = 10;
private Paint mPaint;
//矩陣用來縮放
private Matrix mMatrix;
private BitmapShader mBitmapShader;
private RectF mRectF;
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mMatrix = new Matrix();
//獲取自定義的屬性
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RoundImageView);
int defvalue = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,BODER_RADIUS_DEFAULT,getResources().getDisplayMetrics());
mBorderRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius,defvalue);
type = a.getInt(R.styleable.RoundImageView_type,TYPE_CIRCLE);
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//爲圓形圖片,所以應該讓寬高保持一致,獲得半徑大小
if (type == TYPE_CIRCLE){
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = size / 2;
setMeasuredDimension(size, size);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRectF = new RectF(0,0,getWidth(),getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null){
return;
}
setUpShader();
if (type == TYPE_ROUND){
canvas.drawRoundRect(mRectF,mBorderRadius,mBorderRadius,mPaint);
}else {
canvas.drawCircle(mRadius,mRadius,mRadius,mPaint);
}
}
private void setUpShader() {
Drawable drawable = getDrawable();
if (drawable == null){
return;
}
Bitmap bitmap = drawableToBitmap(drawable);
//初始化BitmapShader,傳入bitmap對象,在指定區域內繪製bitmap
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//計算縮放比例
float scale = 1.0f;
if (type == TYPE_CIRCLE){
//根據最小寬高,設置比例
int size = Math.min(bitmap.getWidth(),bitmap.getHeight());
scale = mRadius * 2.0f/ size;
}else if (type == TYPE_ROUND){
// 如果圖片的寬或者高與view的寬高不匹配,計算出需要縮放的比例;
// 縮放後的圖片的寬高,一定要大於我們view的寬高;所以我們這裏取大值
scale = Math.max(getMeasuredWidth() * 1.0f / bitmap.getWidth(), getMeasuredHeight() * 1.0f / bitmap.getHeight());
}
//shader的變換矩陣,用於放大或者縮小
mMatrix.setScale(scale,scale);
mBitmapShader.setLocalMatrix(mMatrix);
mPaint.setShader(mBitmapShader);
}
/**
* 將drawable 轉化爲 Bitmap
* @param drawable
* @return
*/
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable){
BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
return bitmapDrawable.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0,0,w,h);
drawable.draw(canvas);
return bitmap;
}
}
3.佈局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:roundview="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<mo.yumf.com.myviews.RoundImageView
android:id="@+id/Roundview"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="20dp"
roundview:borderRadius="5dp"
roundview:type="round"/>
<mo.yumf.com.myviews.RoundImageView
android:id="@+id/Circleview"
android:layout_width="200dp"
android:layout_height="100dp"
roundview:type="circle"
android:layout_marginTop="20dp"/>
</LinearLayout>
關於BitmapShader類
BitmapShader是Shader的子類,可以通過Paint.setShader(Shader shader)來設置。構造方法:
BitmapShader mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
TileMode的取值有三種:
CLAMP :拉伸,這個拉伸的是圖片最後的那一個像素;橫向的最後一個橫行像素,不斷的重複,縱項的那一列像素,不斷的重複;
REPEAT: 重複,就是橫向、縱向不斷重複這個bitmap;
MIRROR :鏡像,橫向不斷翻轉重複,縱向不斷翻轉重複;
BitmapShader通過設置給mPaint,然後用這個mPaint繪圖時,就會根據你設置的TileMode,對繪製區域進行着色。
這裏需要注意一點:就是BitmapShader是從你的畫布的左上角開始繪製的,不在view的右下角繪製個正方形,它不會在你正方形的左上角開始。