Android自定义圆形控件CircleImageView

之前使用过,现在做下记录

  • 自定义圆形控件github地址:

https://github.com/hdodenhof/CircleImageView

  • 使用方式

<de.hdodenhof.circleimageview.CircleImageView 
   xmlns:app="http://schemas.android.com/apk/res-auto" 
   android:id="@+id/profile_image"
   android:layout_width="96dp" 
   android:layout_height="96dp"
   android:src="@drawable/profile"
   app:civ_border_width="2dp" 
   app:civ_border_color="#FF000000"/>
  • 自定义控件源码

/*

* Copyright 2014 - 2016 Henning Dodenhof

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*    http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

packagede.hdodenhof.circleimageview;

importandroid.content.Context;

importandroid.content.res.TypedArray;

importandroid.graphics.Bitmap;

importandroid.graphics.BitmapShader;

importandroid.graphics.Canvas;

importandroid.graphics.Color;

importandroid.graphics.ColorFilter;

importandroid.graphics.Matrix;

importandroid.graphics.Paint;

importandroid.graphics.RectF;

importandroid.graphics.Shader;

importandroid.graphics.drawable.BitmapDrawable;

importandroid.graphics.drawable.ColorDrawable;

importandroid.graphics.drawable.Drawable;

importandroid.net.Uri;

importandroid.support.annotation.ColorInt;

importandroid.support.annotation.ColorRes;

importandroid.support.annotation.DrawableRes;

importandroid.util.AttributeSet;

importandroid.widget.ImageView;

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;

privatestaticfinalintDEFAULT_FILL_COLOR=Color.TRANSPARENT;

privatestaticfinalbooleanDEFAULT_BORDER_OVERLAY=false;

privatefinalRectFmDrawableRect=newRectF();

privatefinalRectFmBorderRect=newRectF();

privatefinalMatrixmShaderMatrix=newMatrix();

privatefinalPaintmBitmapPaint=newPaint();

privatefinalPaintmBorderPaint=newPaint();

privatefinalPaintmFillPaint=newPaint();

privateintmBorderColor=DEFAULT_BORDER_COLOR;

privateintmBorderWidth=DEFAULT_BORDER_WIDTH;

privateintmFillColor=DEFAULT_FILL_COLOR;

privateBitmapmBitmap;

privateBitmapShadermBitmapShader;

privateintmBitmapWidth;

privateintmBitmapHeight;

privatefloatmDrawableRadius;

privatefloatmBorderRadius;

privateColorFiltermColorFilter;

privatebooleanmReady;

privatebooleanmSetupPending;

privatebooleanmBorderOverlay;

privatebooleanmDisableCircularTransformation;

publicCircleImageView(Contextcontext) {

super(context);

init();

}

publicCircleImageView(Contextcontext,AttributeSetattrs) {

this(context, attrs,0);

}

publicCircleImageView(Contextcontext,AttributeSetattrs,intdefStyle) {

super(context, attrs, defStyle);

TypedArraya=context.obtainStyledAttributes(attrs,R.styleable.CircleImageView, defStyle,0);

mBorderWidth=a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width,DEFAULT_BORDER_WIDTH);

mBorderColor=a.getColor(R.styleable.CircleImageView_civ_border_color,DEFAULT_BORDER_COLOR);

mBorderOverlay=a.getBoolean(R.styleable.CircleImageView_civ_border_overlay,DEFAULT_BORDER_OVERLAY);

mFillColor=a.getColor(R.styleable.CircleImageView_civ_fill_color,DEFAULT_FILL_COLOR);

a.recycle();

init();

}

privatevoidinit() {

super.setScaleType(SCALE_TYPE);

mReady=true;

if(mSetupPending) {

setup();

mSetupPending=false;

}

}

@Override

publicScaleTypegetScaleType() {

returnSCALE_TYPE;

}

@Override

publicvoidsetScaleType(ScaleTypescaleType) {

if(scaleType!=SCALE_TYPE) {

thrownewIllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));

}

}

@Override

publicvoidsetAdjustViewBounds(booleanadjustViewBounds) {

if(adjustViewBounds) {

thrownewIllegalArgumentException("adjustViewBounds not supported.");

}

}

@Override

protectedvoidonDraw(Canvascanvas) {

if(mDisableCircularTransformation) {

super.onDraw(canvas);

return;

}

if(mBitmap==null) {

return;

}

if(mFillColor!=Color.TRANSPARENT) {

canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint);

}

canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint);

if(mBorderWidth>0) {

canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);

}

}

@Override

protectedvoidonSizeChanged(intw,inth,intoldw,intoldh) {

super.onSizeChanged(w, h, oldw, oldh);

setup();

}

@Override

publicvoidsetPadding(intleft,inttop,intright,intbottom) {

super.setPadding(left, top, right, bottom);

setup();

}

@Override

publicvoidsetPaddingRelative(intstart,inttop,intend,intbottom) {

super.setPaddingRelative(start, top, end, bottom);

setup();

}

publicintgetBorderColor() {

returnmBorderColor;

}

publicvoidsetBorderColor(@ColorIntintborderColor) {

if(borderColor==mBorderColor) {

return;

}

mBorderColor=borderColor;

mBorderPaint.setColor(mBorderColor);

invalidate();

}

/**

* @deprecated Use {@link #setBorderColor(int)} instead

*/

@Deprecated

publicvoidsetBorderColorResource(@ColorResintborderColorRes) {

setBorderColor(getContext().getResources().getColor(borderColorRes));

}

/**

* Return the color drawn behind the circle-shaped drawable.

*

* @return The color drawn behind the drawable

*

* @deprecated Fill color support is going to be removed in the future

*/

@Deprecated

publicintgetFillColor() {

returnmFillColor;

}

/**

* Set a color to be drawn behind the circle-shaped drawable. Note that

* this has no effect if the drawable is opaque or no drawable is set.

*

* @param fillColor The color to be drawn behind the drawable

*

* @deprecated Fill color support is going to be removed in the future

*/

@Deprecated

publicvoidsetFillColor(@ColorIntintfillColor) {

if(fillColor==mFillColor) {

return;

}

mFillColor=fillColor;

mFillPaint.setColor(fillColor);

invalidate();

}

/**

* Set a color to be drawn behind the circle-shaped drawable. Note that

* this has no effect if the drawable is opaque or no drawable is set.

*

* @param fillColorRes The color resource to be resolved to a color and

*                    drawn behind the drawable

*

* @deprecated Fill color support is going to be removed in the future

*/

@Deprecated

publicvoidsetFillColorResource(@ColorResintfillColorRes) {

setFillColor(getContext().getResources().getColor(fillColorRes));

}

publicintgetBorderWidth() {

returnmBorderWidth;

}

publicvoidsetBorderWidth(intborderWidth) {

if(borderWidth==mBorderWidth) {

return;

}

mBorderWidth=borderWidth;

setup();

}

publicbooleanisBorderOverlay() {

returnmBorderOverlay;

}

publicvoidsetBorderOverlay(booleanborderOverlay) {

if(borderOverlay==mBorderOverlay) {

return;

}

mBorderOverlay=borderOverlay;

setup();

}

publicbooleanisDisableCircularTransformation() {

returnmDisableCircularTransformation;

}

publicvoidsetDisableCircularTransformation(booleandisableCircularTransformation) {

if(mDisableCircularTransformation==disableCircularTransformation) {

return;

}

mDisableCircularTransformation=disableCircularTransformation;

initializeBitmap();

}

@Override

publicvoidsetImageBitmap(Bitmapbm) {

super.setImageBitmap(bm);

initializeBitmap();

}

@Override

publicvoidsetImageDrawable(Drawabledrawable) {

super.setImageDrawable(drawable);

initializeBitmap();

}

@Override

publicvoidsetImageResource(@DrawableResintresId) {

super.setImageResource(resId);

initializeBitmap();

}

@Override

publicvoidsetImageURI(Uriuri) {

super.setImageURI(uri);

initializeBitmap();

}

@Override

publicvoidsetColorFilter(ColorFiltercf) {

if(cf==mColorFilter) {

return;

}

mColorFilter=cf;

applyColorFilter();

invalidate();

}

@Override

publicColorFiltergetColorFilter() {

returnmColorFilter;

}

privatevoidapplyColorFilter() {

if(mBitmapPaint!=null) {

mBitmapPaint.setColorFilter(mColorFilter);

}

}

privateBitmapgetBitmapFromDrawable(Drawabledrawable) {

if(drawable==null) {

returnnull;

}

if(drawableinstanceofBitmapDrawable) {

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(Exceptione) {

e.printStackTrace();

returnnull;

}

}

privatevoidinitializeBitmap() {

if(mDisableCircularTransformation) {

mBitmap=null;

}else{

mBitmap=getBitmapFromDrawable(getDrawable());

}

setup();

}

privatevoidsetup() {

if(!mReady) {

mSetupPending=true;

return;

}

if(getWidth()==0&&getHeight()==0) {

return;

}

if(mBitmap==null) {

invalidate();

return;

}

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);

mFillPaint.setStyle(Paint.Style.FILL);

mFillPaint.setAntiAlias(true);

mFillPaint.setColor(mFillColor);

mBitmapHeight=mBitmap.getHeight();

mBitmapWidth=mBitmap.getWidth();

mBorderRect.set(calculateBounds());

mBorderRadius=Math.min((mBorderRect.height()-mBorderWidth)/2.0f, (mBorderRect.width()-mBorderWidth)/2.0f);

mDrawableRect.set(mBorderRect);

if(!mBorderOverlay&&mBorderWidth>0) {

mDrawableRect.inset(mBorderWidth-1.0f, mBorderWidth-1.0f);

}

mDrawableRadius=Math.min(mDrawableRect.height()/2.0f, mDrawableRect.width()/2.0f);

applyColorFilter();

updateShaderMatrix();

invalidate();

}

privateRectFcalculateBounds() {

intavailableWidth=getWidth()-getPaddingLeft()-getPaddingRight();

intavailableHeight=getHeight()-getPaddingTop()-getPaddingBottom();

intsideLength=Math.min(availableWidth, availableHeight);

floatleft=getPaddingLeft()+(availableWidth-sideLength)/2f;

floattop=getPaddingTop()+(availableHeight-sideLength)/2f;

returnnewRectF(left, top, left+sideLength, top+sideLength);

}

privatevoidupdateShaderMatrix() {

floatscale;

floatdx=0;

floatdy=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.setScale(scale, scale);

mShaderMatrix.postTranslate((int) (dx+0.5f)+mDrawableRect.left, (int) (dy+0.5f)+mDrawableRect.top);

mBitmapShader.setLocalMatrix(mShaderMatrix);

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容