前段时间做了个在线医生的项目,老板觉得头像用圆的好看, 于是,有了我接下来这个自定义ImageView圆图实现。项目遇到了需要实现圆头像的编辑显示,Universal就已经提供了这个显示RoundedBitmapDisplayer这个类实现了圆图功能。看它的代码可以发现是实现的Drawable
[java] view plain copy
public static class RoundedDrawable extends Drawable {
protected final float cornerRadius;
protected final int margin;
protected final RectF mRect = new RectF(),
mBitmapRect;
protected final BitmapShader bitmapShader;
protected final Paint paint;
public RoundedDrawable(Bitmap bitmap, int cornerRadius, int margin) {
this.cornerRadius = cornerRadius;
this.margin = margin;
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapRect = new RectF (margin, margin, bitmap.getWidth() - margin, bitmap.getHeight() - margin);
paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(bitmapShader);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(margin, margin, bounds.width() - margin, bounds.height() - margin);
// Resize the original bitmap to fit the new bound
Matrix shaderMatrix = new Matrix();
shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
bitmapShader.setLocalMatrix(shaderMatrix);
}
@Override
public void draw(Canvas canvas) {
canvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
}
其实总结下来,上面圆图实现步骤就是 1、通过bitmap初始化位图着色器BitmapShader类,2、计算bitmap原始图片的rect,3、计算放置图片需要的rect。4、使用Matrix类对两个rect进行压缩,然后复制给BitmapShader着色器里去。最后是画布画图。(刚开始一直以为shader是阴影的意思,原来有道一下是着色器的意思,这个翻译其实对我理解代码还是很重要的,所以不要想当然,要勤奋点,这个是优秀程序员必备要素。)
最后我要实现的是继承ImageView实现圆图
[java] view plain copy
public class URoundedImageView extends ImageView {
private Paint mBitmapPaint,mBackgroundPaint;
private BitmapShader mBitmapShader;
private RectF mBitmapRect , mRect;
private int borderWidth;
private Bitmap mBitmap;
private Matrix shaderMatrix;
public URoundedImageView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public URoundedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public URoundedImageView(Context context) {
super(context);
init();
}
private void init(){
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
mBackgroundPaint = new Paint();
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setColor(Color.WHITE);
borderWidth = 5;
mRect = new RectF();
shaderMatrix = new Matrix();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
mBitmap = ((BitmapDrawable) getDrawable()).getBitmap();
if (getWidth() == 0 || getHeight() == 0 || mBitmap == null) {
return;
}
int w = getWidth();
int h = getHeight();
int radius = Math.min(w, h) / 2;
canvas.drawCircle(w / 2, h / 2, radius, mBackgroundPaint);
//传入bitmap初始化位图着色器
if (mBitmapShader == null) {
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
}
if (mBitmapRect == null) {
mBitmapRect = new RectF(borderWidth, borderWidth,
mBitmap.getWidth() - borderWidth, mBitmap.getHeight()
- borderWidth);
}
mBitmapPaint.setShader(mBitmapShader);
mRect.set(borderWidth, borderWidth, w - borderWidth, h - borderWidth);
//对bitmap原始图进行缩放
shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
mBitmapShader.setLocalMatrix(shaderMatrix);
canvas.drawRoundRect(mRect, radius, radius, mBitmapPaint);
}
}
刚开始写的不够规范,直接在ondraw方法里面new一些需要的对象,lint提醒我们Avoid object allocations during draw/layout operations (preallocate and reuse instead)这个warning。因为ondraw会不断调用,如果一直new对象的话会吃内存。所以为了避免重复new对象,根据自己的需求进行判空操作。具体根据自己需求来优化代码,有时候为了达到需求也没办法做到在ondraw方法里不出现重复new对象的现象。
(用的时候,直接在你的xml里面定义 绝对路径引用 我上传的ImageView 就可以,其他的在你的代码里和imageView、一样的操作。)
|
|