因为项目需求,需要实现圆形头像框,在参考了鸿洋大神的 http://blog.csdn.net/lmj623565791/article/details/41967509 文章之后,通过BitmapShader实现了圆形头像框,下面是效果展示以及具体的实现过程。
想要实现圆形头像框,有以下几个注意点:
1.保持控件的宽高一致:因为是圆形头像框,所以需要强行设置控件的height和width一致。
2.缩放图片至合适的大小: 图片的大小可能比我们的控件大,也可能比我们的控件小,需要通过缩放图片的大小以适应我们的控件。
3.在控件区域内绘制圆形头像: 我们不能直接将控件设置为圆形,所以实现圆形头像框实际上就是将图片以圆形的样式绘制在我们的控件上。
所以,只要我们能够实现以上三点,就能够实现圆形头像框的绘制。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 取view长宽的较小值,除以2作为圆的半径,并重新设置View的大小
mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = mWidth / 2;
setMeasuredDimension(mWidth, mWidth);
}
复写onMeasure方法,通过Math.min方法比较获取宽高的较小值后,利用setMeasuredDimension强制使得宽高一致。圆的半径为宽高最小值的1/2。
/**
* 获取缩放比例
*/
private float getScale(Bitmap bmp) {
float scale;
int bSize = Math.min(bmp.getWidth(), bmp.getHeight());
scale = mWidth * 1.0f / bSize;
return scale;
}
首先,我们要获取图片的缩放比例。在这里,我采用图片宽高的较小值与控件的width作比较(mWidth是计算之后的宽,与高度保持一致大小),因为使用较大值进行缩放之后的图片不能填满我们的控件。
// shader的变换矩阵,对图片进行缩放
mMatrix.setScale(scale, scale);
获取了相应的scale缩放比之后,利用Matrix进行缩放。
我们可以通过BitmapShader来实现将图片以圆形样式绘制的过程。
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
Bitmap bmp = drawableToBitmap(drawable);
if (bmp == null) {
return;
}
// 将bmp作为着色器,就是在指定区域内绘制bmp
if (mBitmapShader == null) {
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
}
float scale = getScale(bmp);
// shader的变换矩阵,对图片进行缩放
mMatrix.setScale(scale, scale);
// 设置变换矩阵
mBitmapShader.setLocalMatrix(mMatrix);
// 设置shader
mBitmapPaint.setShader(mBitmapShader);
将Drawable转换成Bitmap后,初始化mBitmapShader,并设置宽高的TileMode为CLAMP拉伸模式。最后设置变换矩阵,画笔setShader之后就可以进行draw了。
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
setUpShader();
canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
}
绘制就是利用canvas画个圆,mRadius是圆的半径,mBitmapPaint是绘制的画笔。
/**
* 圆形头像框控件
*
* @author [email protected]
*/
public class CircleImageView extends AppCompatImageView {
/**
* 绘图的Paint
**/
private Paint mBitmapPaint;
/**
* 圆角的半径
**/
private int mRadius;
/**
* 3x3 矩阵,主要用于缩小放大
**/
private Matrix mMatrix;
/**
* 渲染图像,使用图像为绘制图形着色
**/
private BitmapShader mBitmapShader;
/**
* view的宽度
**/
private int mWidth;
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
// 初始化变量
mMatrix = new Matrix();
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 取view长宽的较小值,除以2作为圆的半径,并重新设置View的大小
mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = mWidth / 2;
setMeasuredDimension(mWidth, mWidth);
}
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
setUpShader();
canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
}
/**
* 初始化BitmapShader
*/
private void setUpShader() {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
Bitmap bmp = drawableToBitmap(drawable);
if (bmp == null) {
return;
}
// 将bmp作为着色器,就是在指定区域内绘制bmp
if (mBitmapShader == null) {
mBitmapShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
}
float scale = getScale(bmp);
// shader的变换矩阵,对图片进行缩放
mMatrix.setScale(scale, scale);
// 设置变换矩阵
mBitmapShader.setLocalMatrix(mMatrix);
// 设置shader
mBitmapPaint.setShader(mBitmapShader);
}
/**
* 获取缩放比例
*/
private float getScale(Bitmap bmp) {
float scale;
int bSize = Math.min(bmp.getWidth(), bmp.getHeight());
scale = mWidth * 1.0f / bSize;
return scale;
}
/**
* drawable转bitmap
*/
private Bitmap drawableToBitmap(Drawable drawable) {
// 如果drawable是BitmapDrawable的一个实例,则直接返回getBitmap
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
// 获取drawable固有的宽高
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
// 创建一个bitmap为canvas的操作对象,绘制的内容显示在bitmap上
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;
}
}