Created
May 31, 2016 12:58
-
-
Save brucetoo/d4867b42422c7902a60e92c84aebc93a to your computer and use it in GitHub Desktop.
Circle and Round imageView widget
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.netease.cc.dhsdkcore.widget; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapShader; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.Matrix; | |
import android.graphics.Paint; | |
import android.graphics.RectF; | |
import android.graphics.Shader; | |
import android.graphics.drawable.BitmapDrawable; | |
import android.graphics.drawable.ColorDrawable; | |
import android.graphics.drawable.Drawable; | |
import android.support.annotation.IntDef; | |
import android.util.AttributeSet; | |
import android.util.TypedValue; | |
import android.widget.ImageView; | |
import com.netease.cc.dhsdkcore.R; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
/** | |
<declare-styleable name="CircleImageView"> | |
<attr name="border_width" format="dimension"/> | |
<attr name="border_color" format="color"/> | |
<attr name="border_fillstyle" format="boolean"/> | |
<attr name="border_type"> | |
<enum name="circle" value="0" /> | |
<enum name="round" value="1" /> | |
</attr> | |
<attr name="border_radius" format="dimension" /> | |
</declare-styleable> | |
*/ | |
public class CircleImageView extends ImageView { | |
@Retention(RetentionPolicy.SOURCE) | |
@IntDef({TYPE_CIRCLE,TYPE_ROUND}) | |
public @interface TYPE{} | |
private int type; | |
public static final int TYPE_CIRCLE = 0; | |
public static final int TYPE_ROUND = 1; | |
private RectF mRoundRect; | |
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; | |
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.TRANSPARENT; | |
private static final boolean DEFAULT_BORDER_FILLSTYLE = false; | |
private static final int DEFAULT_BORDER_RADIUS = 10; | |
private final RectF mDrawableRect = new RectF(); | |
private final RectF mBorderRect = new RectF(); | |
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 boolean mFillStyle = DEFAULT_BORDER_FILLSTYLE; | |
private Bitmap mBitmap; | |
private BitmapShader mBitmapShader; | |
private int mBitmapWidth; | |
private int mBitmapHeight; | |
private float mDrawableRadius; | |
private float mBorderRadius; | |
private boolean mReady; | |
private boolean mSetupPending; | |
public CircleImageView(Context context) { | |
super(context); | |
initSetting(); | |
} | |
public CircleImageView(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
initSetting(); | |
} | |
public CircleImageView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
super.setScaleType(SCALE_TYPE); | |
// int[] imageStyle = IdentifierUtil.getStyleableArray(context, "CircleImageView"); | |
// TypedArray a = context.obtainStyledAttributes(attrs, imageStyle, defStyle, 0); | |
// mBorderWidth = a.getDimensionPixelSize(IdentifierUtil.getStyleable(context, "CircleImageView_border_width"), DEFAULT_BORDER_WIDTH); | |
// mBorderColor = a.getColor(IdentifierUtil.getStyleable(context, "CircleImageView_border_color"), DEFAULT_BORDER_COLOR); | |
// mFillStyle = a.getBoolean(IdentifierUtil.getStyleable(context, "CircleImageView_border_fillstyle"), false); | |
// mBorderRadius = a.getDimensionPixelSize( | |
// IdentifierUtil.getStyleable(getContext(), "CircleImageView_border_radius"), (int) dp2px(DEFAULT_BORDER_RADIUS));// 默认为10dp | |
// type = a.getInt(IdentifierUtil.getStyleable(getContext(), "CircleImageView_border_type"), TYPE_CIRCLE); | |
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView,0,0); | |
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width,DEFAULT_BORDER_WIDTH); | |
mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR); | |
mFillStyle = a.getBoolean(R.styleable.CircleImageView_border_fillstyle,false); | |
mBorderRadius = a.getDimensionPixelSize(R.styleable.CircleImageView_border_radius,(int) dp2px(DEFAULT_BORDER_RADIUS)); | |
type = a.getInt(R.styleable.CircleImageView_border_type, TYPE_CIRCLE); | |
a.recycle(); | |
initSetting(); | |
} | |
/** | |
* This method must be revoked in construct method | |
* to init setting config | |
*/ | |
public void initSetting() { | |
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; | |
} | |
if(type == TYPE_CIRCLE) { | |
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); | |
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); | |
}else if(type == TYPE_ROUND){ //add round radius support | |
//draw border | |
canvas.drawRoundRect(mRoundRect,mBorderRadius,mBorderRadius,mBorderPaint); | |
//draw bitmap | |
canvas.drawRoundRect(mRoundRect,mBorderRadius,mDrawableRadius,mBitmapPaint); | |
} | |
} | |
@Override | |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
super.onSizeChanged(w, h, oldw, oldh); | |
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; | |
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.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); | |
drawable.draw(canvas); | |
return bitmap; | |
} catch (OutOfMemoryError e) { | |
return null; | |
} | |
} | |
/** | |
* First time you call this method,mBitmap could be null | |
* So we need revoke this method in {@link #setImageResource(int)} | |
* {@link #setImageBitmap(Bitmap)} {@link #setImageDrawable(Drawable)} (int)} | |
* to {@param mBitmap} is not null | |
*/ | |
private void setup() { | |
mRoundRect = new RectF(0, 0, getWidth(), getHeight()); | |
if (!mReady) { | |
mSetupPending = true; | |
return; | |
} | |
if (mBitmap == null) { | |
return; | |
} | |
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); | |
mBitmapPaint.setAntiAlias(true); | |
mBitmapPaint.setShader(mBitmapShader); | |
if(mFillStyle) { | |
mBorderPaint.setStyle(Paint.Style.FILL); | |
} else { | |
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()); | |
if(type == TYPE_CIRCLE) { | |
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2); | |
} | |
mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth); | |
if(type == TYPE_CIRCLE) { | |
mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); | |
}else { | |
mDrawableRadius = mBorderRadius; | |
} | |
updateShaderMatrix(); | |
invalidate(); | |
} | |
private void updateShaderMatrix() { | |
float scale; | |
float dx = 0; | |
float dy = 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) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth); | |
mBitmapShader.setLocalMatrix(mShaderMatrix); | |
} | |
public int getBorderColor() { | |
return mBorderColor; | |
} | |
public void setBorderColor(int borderColor) { | |
if (borderColor == mBorderColor) { | |
return; | |
} | |
mBorderColor = borderColor; | |
mBorderPaint.setColor(mBorderColor); | |
invalidate(); | |
} | |
public int getType() { | |
return type; | |
} | |
public void setType(@TYPE int type) { | |
this.type = type; | |
setup(); | |
} | |
public float getBorderRadius() { | |
return mBorderRadius; | |
} | |
public void setBorderRadius(float mBorderRadius) { | |
this.mBorderRadius = dp2px(mBorderRadius); | |
setup(); | |
} | |
public int getBorderWidth() { | |
return mBorderWidth; | |
} | |
public void setBorderWidth(int borderWidth) { | |
if (borderWidth == mBorderWidth) { | |
return; | |
} | |
mBorderWidth = borderWidth; | |
setup(); | |
} | |
private float dp2px(float dp){ | |
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment