Android圆角头像工具类详解
很多android应用都用到了圆角头像,或者一些圆角图片处理起来比较麻烦,直接上圆角图片工具类
publicclassCircleImageViewextendsImageView{
//缩放类型
privatestaticfinalScaleTypeSCALE_TYPE=ScaleType.CENTER_CROP;
privatestaticfinalBitmap.ConfigBITMAP_CONFIG=Bitmap.Config.ARGB_8888;
privatestaticfinalintCOLORDRAWABLE_DIMENSION=2;
//默认边界宽度
privatestaticfinalintDEFAULT_BORDER_WIDTH=0;
//默认边界颜色
privatestaticfinalintDEFAULT_BORDER_COLOR=Color.BLACK;
privatestaticfinalbooleanDEFAULT_BORDER_OVERLAY=false;
privatefinalRectFmDrawableRect=newRectF();
privatefinalRectFmBorderRect=newRectF();
privatefinalMatrixmShaderMatrix=newMatrix();
//这个画笔最重要的是关联了mBitmapShader
//使canvas在执行的时候可以切割原图片(mBitmapShader是关联了原图的bitmap的)
privatefinalPaintmBitmapPaint=newPaint();
//这个描边,则与本身的原图bitmap没有任何关联,
privatefinalPaintmBorderPaint=newPaint();
//这里定义了圆形边缘的默认宽度和颜色
privateintmBorderColor=DEFAULT_BORDER_COLOR;
privateintmBorderWidth=DEFAULT_BORDER_WIDTH;
privateBitmapmBitmap;
privateBitmapShadermBitmapShader;//位图渲染
privateintmBitmapWidth;//位图宽度
privateintmBitmapHeight;//位图高度
privatefloatmDrawableRadius;//图片半径
privatefloatmBorderRadius;//带边框的的图片半径
privateColorFiltermColorFilter;
//初始false
privatebooleanmReady;
privatebooleanmSetupPending;
privatebooleanmBorderOverlay;
//构造函数
publicCircleImageView(Contextcontext){
super(context);
init();
}
//构造函数
publicCircleImageView(Contextcontext,AttributeSetattrs){
this(context,attrs,0);
}
/**
*构造函数
*/
publicCircleImageView(Contextcontext,AttributeSetattrs,intdefStyle){
super(context,attrs,defStyle);
//通过obtainStyledAttributes获得一组值赋给TypedArray(数组),
//这一组值来自于res/values/attrs.xml中的name="CircleImageView"的declare-styleable中。
TypedArraya=context.obtainStyledAttributes(attrs,
R.styleable.CircleImageView,defStyle,0);
//通过TypedArray提供的一系列方法getXXXX取得我们在xml里定义的参数值;
//获取边界的宽度
mBorderWidth=a.getDimensionPixelSize(
R.styleable.CircleImageView_border_size,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);
//调用recycle()回收TypedArray,以便后面重用
a.recycle();
init();
}
/**
*作用就是保证第一次执行setup函数里下面代码要在构造函数执行完毕时调用
*/
privatevoidinit(){
//在这里ScaleType被强制设定为CENTER_CROP,就是将图片水平垂直居中,进行缩放。
super.setScaleType(SCALE_TYPE);
mReady=true;
if(mSetupPending){
setup();
mSetupPending=false;
}
}
@Override
publicScaleTypegetScaleType(){
returnSCALE_TYPE;
}
/**
*这里明确指出此种imageview只支持CENTER_CROP这一种属性
*
*@paramscaleType
*/
@Override
publicvoidsetScaleType(ScaleTypescaleType){
if(scaleType!=SCALE_TYPE){
thrownewIllegalArgumentException(String.format(
"ScaleType%snotsupported.",scaleType));
}
}
@Override
publicvoidsetAdjustViewBounds(booleanadjustViewBounds){
if(adjustViewBounds){
thrownewIllegalArgumentException(
"adjustViewBoundsnotsupported.");
}
}
@Override
protectedvoidonDraw(Canvascanvas){
//如果图片不存在就不画
if(getDrawable()==null){
return;
}
//绘制内圆形图片画笔为mBitmapPaint
canvas.drawCircle(getWidth()/2,getHeight()/2,mDrawableRadius,
mBitmapPaint);
//如果圆形边缘的宽度不为0我们还要绘制带边界的外圆形边界画笔为mBorderPaint
if(mBorderWidth!=0){
canvas.drawCircle(getWidth()/2,getHeight()/2,mBorderRadius,
mBorderPaint);
}
}
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
setup();
}
publicintgetBorderColor(){
returnmBorderColor;
}
publicvoidsetBorderColor(intborderColor){
if(borderColor==mBorderColor){
return;
}
mBorderColor=borderColor;
mBorderPaint.setColor(mBorderColor);
invalidate();
}
publicvoidsetBorderColorResource(@ColorResintborderColorRes){
setBorderColor(getContext().getResources().getColor(borderColorRes));
}
publicintgetBorderWidth(){
returnmBorderWidth;
}
publicvoidsetBorderWidth(intborderWidth){
if(borderWidth==mBorderWidth){
return;
}
mBorderWidth=borderWidth;
setup();
}
publicbooleanisBorderOverlay(){
returnmBorderOverlay;
}
publicvoidsetBorderOverlay(booleanborderOverlay){
if(borderOverlay==mBorderOverlay){
return;
}
mBorderOverlay=borderOverlay;
setup();
}
/**
*以下四个函数都是复写ImageView的setImageXxx()方法注意这个函数先于构造函数调用之前调用
*
*@parambm
*/
@Override
publicvoidsetImageBitmap(Bitmapbm){
super.setImageBitmap(bm);
mBitmap=bm;
setup();
}
@Override
publicvoidsetImageDrawable(Drawabledrawable){
super.setImageDrawable(drawable);
mBitmap=getBitmapFromDrawable(drawable);
setup();
}
@Override
publicvoidsetImageResource(@DrawableResintresId){
super.setImageResource(resId);
mBitmap=getBitmapFromDrawable(getDrawable());
setup();
}
@Override
publicvoidsetImageURI(Uriuri){
super.setImageURI(uri);
mBitmap=getBitmapFromDrawable(getDrawable());
setup();
}
@Override
publicvoidsetColorFilter(ColorFiltercf){
if(cf==mColorFilter){
return;
}
mColorFilter=cf;
mBitmapPaint.setColorFilter(mColorFilter);
invalidate();
}
/**
*Drawable转Bitmap
*
*@paramdrawable
*@return
*/
privateBitmapgetBitmapFromDrawable(Drawabledrawable){
if(drawable==null){
returnnull;
}
if(drawableinstanceofBitmapDrawable){
//通常来说我们的代码就是执行到这里就返回了。返回的就是我们最原始的bitmap
return((BitmapDrawable)drawable).getBitmap();
}
try{
Bitmapbitmap;
if(drawableinstanceofColorDrawable){
bitmap=Bitmap.createBitmap(COLORDRAWABLE_DIMENSION,
COLORDRAWABLE_DIMENSION,BITMAP_CONFIG);
}else{
bitmap=Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),BITMAP_CONFIG);
}
Canvascanvas=newCanvas(bitmap);
drawable.setBounds(0,0,canvas.getWidth(),canvas.getHeight());
drawable.draw(canvas);
returnbitmap;
}catch(OutOfMemoryErrore){
returnnull;
}
}
/**
*这个函数很关键,进行图片画笔边界画笔(Paint)一些重绘参数初始化:
*构建渲染器BitmapShader用Bitmap来填充绘制区域,设置样式以及内外圆半径计算等,
*以及调用updateShaderMatrix()函数和invalidate()函数;
*/
privatevoidsetup(){
//因为mReady默认值为false,所以第一次进这个函数的时候if语句为真进入括号体内
//设置mSetupPending为true然后直接返回,后面的代码并没有执行。
if(!mReady){
mSetupPending=true;
return;
}
//防止空指针异常
if(mBitmap==null){
return;
}
//构建渲染器,用mBitmap位图来填充绘制区域,参数值代表如果图片太小的话就直接拉伸
mBitmapShader=newBitmapShader(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();
//设置含边界显示区域,取的是CircleImageView的布局实际大小,为方形,查看xml也就是160dp(240px)
//getWidth得到是某个view的实际尺寸
mBorderRect.set(0,0,getWidth(),getHeight());
//计算
//圆形带边界部分(外圆)的最小半径,取mBorderRect的宽高减去一个边缘大小的一半的较小值(这个地方我比较纳闷为什么求外圆半径需要先减去一个边缘大小)
mBorderRadius=Math.min((mBorderRect.height()-mBorderWidth)/2,
(mBorderRect.width()-mBorderWidth)/2);
//初始图片显示区域为mBorderRect(CircleImageView的布局实际大小)
mDrawableRect.set(mBorderRect);
if(!mBorderOverlay){
//demo里始终执行
//通过inset方法
//使得图片显示的区域从mBorderRect大小上下左右内移边界的宽度形成区域,查看xml边界宽度为2dp(3px),所以方形边长为就是160-4=156dp(234px)
mDrawableRect.inset(mBorderWidth,mBorderWidth);
}
//这里计算的是内圆的最小半径,也即去除边界宽度的半径
mDrawableRadius=Math.min(mDrawableRect.height()/2,
mDrawableRect.width()/2);
//设置渲染器的变换矩阵也即是mBitmap用何种缩放形式填充
updateShaderMatrix();
//手动触发ondraw()函数完成最终的绘制
invalidate();
}
/**
*这个函数为设置BitmapShader的Matrix参数,设置最小缩放比例,平移参数。作用:保证图片损失度最小和始终绘制图片正中央的那部分
*/
privatevoidupdateShaderMatrix(){
floatscale;
floatdx=0;
floatdy=0;
mShaderMatrix.set(null);
//这里不好理解这个不等式也就是(mBitmapWidth/mDrawableRect.width())>
//(mBitmapHeight/mDrawableRect.height())
//取最小的缩放比例
if(mBitmapWidth*mDrawableRect.height()>mDrawableRect.width()
*mBitmapHeight){
//y轴缩放x轴平移使得图片的y轴方向的边的尺寸缩放到图片显示区域(mDrawableRect)一样)
scale=mDrawableRect.height()/(float)mBitmapHeight;
dx=(mDrawableRect.width()-mBitmapWidth*scale)*0.5f;
}else{
//x轴缩放y轴平移使得图片的x轴方向的边的尺寸缩放到图片显示区域(mDrawableRect)一样)
scale=mDrawableRect.width()/(float)mBitmapWidth;
dy=(mDrawableRect.height()-mBitmapHeight*scale)*0.5f;
}
//shaeder的变换矩阵,我们这里主要用于放大或者缩小。
mShaderMatrix.setScale(scale,scale);
//平移
mShaderMatrix.postTranslate((int)(dx+0.5f)+mDrawableRect.left,
(int)(dy+0.5f)+mDrawableRect.top);
//设置变换矩阵
mBitmapShader.setLocalMatrix(mShaderMatrix);
}
}
使用方法
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。