前言
之前我们已经提到过,我们可以使用两种方式来实现圆角图片的效果。一种是使用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的右下角绘制个正方形,它不会在你正方形的左上角开始。