CirclelmageView是一个可以快速创建圆形截图的ImageView。适用于各种可绘制类型。一般用于登陆界面显示用户的头像。实现效果如下所示:
今天特地看了下CirclelmageView的源码,记录如下,参考资料与注意事项都在代码的注释中:
public class CircleImageView extends ImageView { //如果图片比ImageView大,那么则会对其进行缩小,但是并不会像fitCenter或者centerInside那样是根据比例缩放,centerCrop设置后,其缩放的时候会将整个ImageView的边都占据满,不会留出空隙,然后再将图片居中显示,如果图片小的话,就会对其进行扩大,并占满ImageView的边框,再居中显示 //参考:http://www.cnblogs.com/xiaoluo501395377/p/3390909.html private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; //代表32位ARGB位图,参考:http://blog.csdn.net/zidan_2011/article/details/21443147 private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; private static final int COLORDRAWABLE_DIMENSION = 1; private static final int DEFAULT_BORDER_WIDTH = 0; private static final int DEFAULT_BORDER_COLOR = Color.BLACK; private final RectF mDrawableRect = new RectF(); private final RectF mBorderRect = new RectF(); //Matrix参考:http://www.cnblogs.com/mmy0925/archive/2013/01/22/2871009.html private final Matrix mShaderMatrix = new Matrix(); private final Paint mBitmapPaint = new Paint(); private final Paint mBorderPaint = new Paint(); private int mBorderColor = DEFAULT_BORDER_COLOR; private int mBorderWidth = DEFAULT_BORDER_WIDTH; private Bitmap mBitmap; private BitmapShader mBitmapShader; private int mBitmapWidth; private int mBitmapHeight; private float mDrawableRadius; private float mBorderRadius; private boolean mReady; private boolean mSetupPending; //this通常指代当前对象,super通常指代父类,这里this指代当前对象的构造函数,super指代父类(ImageView)的构造函数,根据后面的形参调用相应的构造函数 public CircleImageView(Context context) { super(context); } public CircleImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } //AttributeSet参考:http://blog.csdn.net/eyu8874521/article/details/8552534 public CircleImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); super.setScaleType(SCALE_TYPE); //TypedArray实例是个属性的容器,context.obtainStyledAttributes()方法返回得到。AttributeSet是节点的属性集合 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); a.recycle(); mReady = true; if (mSetupPending) { setup(); mSetupPending = false; } } @Override public ScaleType getScaleType() { return SCALE_TYPE; } @Override public void setScaleType(ScaleType scaleType) { if (scaleType != SCALE_TYPE) { throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); } } @Override protected void onDraw(Canvas canvas) { if (getDrawable() == null) { return; } //画出中心的圆形bitmap canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); //画出图片周围的圆形边界 canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); setup(); } public int getBorderColor() { return mBorderColor; } public void setBorderColor(int borderColor) { if (borderColor == mBorderColor) { return; } mBorderColor = borderColor; mBorderPaint.setColor(mBorderColor); //自动清屏 invalidate(); } public int getBorderWidth() { return mBorderWidth; } public void setBorderWidth(int borderWidth) { if (borderWidth == mBorderWidth) { return; } mBorderWidth = borderWidth; setup(); } @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(int resId) { super.setImageResource(resId); mBitmap = getBitmapFromDrawable(getDrawable()); setup(); } private Bitmap getBitmapFromDrawable(Drawable drawable) { if (drawable == null) { return null; } if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } try { Bitmap bitmap; //将Drawable转化为Bitmap,并根据宽高对图片进行剪切 if (drawable instanceof ColorDrawable) { bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); } else { bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG); } Canvas canvas = new Canvas(bitmap); //设置drawable宽高,将图片绘制在drawable上 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } catch (OutOfMemoryError e) { return null; } } private void setup() { if (!mReady) { mSetupPending = true; return; } if (mBitmap == null) { return; } //Shader.TileMode.CLAMP:replicate the edge color if the shader draws outside of its original bounds mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //Paint的一些属性设置,参考:http://www.cnblogs.com/menlsh/archive/2012/11/18/2776003.html //给Paint加上抗锯齿标志。然后将Paint对象作为参数传给canvas的绘制方法 mBitmapPaint.setAntiAlias(true); //对图片进行渲染,参考:http://www.cnblogs.com/menlsh/archive/2012/12/09/2810372.html mBitmapPaint.setShader(mBitmapShader); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStrokeWidth(mBorderWidth); mBitmapHeight = mBitmap.getHeight(); mBitmapWidth = mBitmap.getWidth(); //设置大小,计算半径 mBorderRect.set(0, 0, getWidth(), getHeight()); mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2); mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth); mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); updateShaderMatrix(); invalidate(); } //更新渲染矩阵 private void updateShaderMatrix() { float scale; float dx = 0; float dy = 0; mShaderMatrix.set(null); //根据mBitmap与mDrawable的宽高,对图片进行缩放处理 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.setScale(scale, scale); mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth); mBitmapShader.setLocalMatrix(mShaderMatrix); } }
参考文章:git-osc自定义控件之:CircleImageView
CircleImageView解析
项目主页:https://github.com/hdodenhof/CircleImageView