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); } }
使用方法
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。