生活中我们见到的大多数头像都变成圆形头像,因为圆形可以给客户一种亲和感,更能被客户接受。而我们Android5.0之前,想要使用圆形头像必须要自己来手写,5.0之后自带了圆形头像为我们开发人员剩了好多事情。
闲话不多说了,直接来看一下效果。
实现分为下面几步:
1.自定义属性(attr.xml);
2.构造方法中获取属性值;
3.调用ondraw()方法;
具体的实现步骤:
1.获取图片
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
mBitmap = bm;
setup();
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
mBitmap = getBitmapFromDrawable(drawable);
setup();
}
@Override
public void setImageResource(@DrawableRes int resId) {
super.setImageResource(resId);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
mBitmap = getBitmapFromDrawable(getDrawable());
setup();
}
2.方法中调用了setup()方法
if (!mReady) {
mSetupPending = true;
return;
}
因为mReady默认是false的,所以只会执行前面的这一句就结束了。
3.调用构造方法获取属性值
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//属性数组
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);
mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);
mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_border_overlay, DEFAULT_BORDER_OVERLAY);
//回收数组
a.recycle();
//调用init()方法
init();
}
4.调用init()方法
private void init() {
super.setScaleType(SCALE_TYPE);
mReady = true;
//执行完setup()方法的前面部分,mSetupPending已经变成了true
if (mSetupPending) {
setup();
mSetupPending = false;
}
}
init()方法的作用只是一用来调节执行顺序的,因为一定要控制先执行构造方法拿到数据之后,然后再去执行setup()方法中的有效部分设置数据。
5.调用setup()方法中的有效部分
private void setup() {
//第一次执行只能执行到这个地方
if (!mReady) {
mSetupPending = true;
return;
}
if (mBitmap == null) {
return;
}
//初始化一个图片渲染器,渲染器
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//设置图片画笔
mBitmapPaint.setAntiAlias(true);
mBitmapPaint.setShader(mBitmapShader);
//设置描边画笔
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor);
mBorderPaint.setStrokeWidth(mBorderWidth);
//获取图片的高度
mBitmapHeight = mBitmap.getHeight();
mBitmapWidth = mBitmap.getWidth();
//创建一个大小和这个view一样大的矩形框
mBorderRect.set(0, 0, getWidth(), getHeight());
//计算外边半径(画圆的时候会用到,外边框的中间处)
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);
mDrawableRect.set(mBorderRect);
if (!mBorderOverlay) {
//控制mDrawableRect比mBorderRect边距空有mBorderWidth
mDrawableRect.inset(mBorderWidth, mBorderWidth);
}
mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2);
updateShaderMatrix();
invalidate();
}
6.调用updateShaderMatrix()方法,用来优化绘制的效果
private void updateShaderMatrix() {
float scale;
float dx = 0;
float dy = 0;
mShaderMatrix.set(null);
//比较是按照宽来缩放还是按照长来缩放
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
scale = mDrawableRect.height() / (float) mBitmapHeight;
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mDrawableRect.width() / (float) mBitmapWidth;
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
}
//mShaderMatrix对象用来对图片进行变换
mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
7.执行invalidate()方法,进行绘制头像
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
if (mBorderWidth != 0) {
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
}
}