package cn.mutils.app.ui;
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.util.AttributeSet;
import android.widget.ImageView;
import java.lang.ref.WeakReference;
import cn.mutils.app.R;
import cn.mutils.app.ui.core.IDefaultDrawableView;
/**
* ImageView of framework.
* <p/>
* Provide circle shape and round rectangle for content image.
*/
@SuppressWarnings({"deprecation", "UnusedAssignment"})
public class ImageIcon extends ImageView implements IDefaultDrawableView {
public static final int SHAPE_CIRCLE = 0;
public static final int SHAPE_RECT = 1;
public static final int SHAPE_ROUND_RECT = 2;
protected static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
protected static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
protected static final int COLOR_DRAWABLE_DIMENSION = 1;
protected static final int DEFAULT_BORDER_WIDTH = 0;
protected static final int DEFAULT_BORDER_COLOR = Color.WHITE;
protected WeakReference<Bitmap> mBitmapRef = new WeakReference<Bitmap>(null);
protected BitmapShader mBitmapShader;
protected Matrix mBitmapShaderMatrix = new Matrix();
protected int mBorderColor = DEFAULT_BORDER_COLOR;
protected int mBorderWidth = DEFAULT_BORDER_WIDTH;
protected int mCornerRadius = 0;
protected Paint mPaint = new Paint();
protected RectF mRectF = new RectF();
protected boolean mReady;
protected Drawable mDefaultDrawable;
protected int mShape = SHAPE_CIRCLE;
public ImageIcon(Context context) {
super(context);
init(context, null);
}
public ImageIcon(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ImageIcon(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
protected void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ImageIcon);
mBorderWidth = typedArray.getDimensionPixelSize(R.styleable.ImageIcon_borderWidth, DEFAULT_BORDER_WIDTH);
mBorderColor = typedArray.getColor(R.styleable.ImageIcon_borderColor, DEFAULT_BORDER_COLOR);
mDefaultDrawable = typedArray.getDrawable(R.styleable.ImageIcon_drawableDefault);
mCornerRadius = typedArray.getDimensionPixelSize(R.styleable.ImageIcon_android_radius, 0);
try {
int shape = typedArray.getInt(R.styleable.ImageIcon_android_shape, 1);
switch (shape) {
case 0:// Rectangle
mShape = SHAPE_RECT;
break;
case 1:// Oval
mShape = SHAPE_CIRCLE;
break;
case 2:// Line
mShape = SHAPE_RECT;
break;
case 3:// Ring
mShape = SHAPE_CIRCLE;
break;
default:
mShape = SHAPE_CIRCLE;
break;
}
} catch (Exception e) {
// RuntimeException
}
if (mCornerRadius != 0 && mShape == SHAPE_RECT) {
mShape = SHAPE_ROUND_RECT;
}
typedArray.recycle();
}
if (mShape == SHAPE_CIRCLE) {
setScaleType(SCALE_TYPE);
}
mReady = true;
setup();
}
@Override
public void setScaleType(ScaleType scaleType) {
if (mShape == SHAPE_CIRCLE) {
if (scaleType != SCALE_TYPE) {
throw new UnsupportedOperationException();
}
}
super.setScaleType(scaleType);
}
public int getShape() {
return mShape;
}
public void setShape(int shape) {
if (mShape == shape) {
return;
}
mShape = shape;
setup();
}
public int getBorderColor() {
return mBorderColor;
}
public void setBorderColor(int borderColor) {
if (mBorderColor == borderColor) {
return;
}
mBorderColor = borderColor;
invalidate();
}
public int getBorderWidth() {
return mBorderWidth;
}
public void setBorderWidth(int borderWidth) {
if (mBorderWidth == borderWidth) {
return;
}
mBorderWidth = borderWidth;
setup();
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
if (mShape != SHAPE_RECT) {
mBitmapRef = new WeakReference<Bitmap>(getBitmapFromDrawable());
}
setup();
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if (mShape != SHAPE_RECT) {
mBitmapRef = new WeakReference<Bitmap>(getBitmapFromDrawable());
}
setup();
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
if (mShape != SHAPE_RECT) {
mBitmapRef = new WeakReference<Bitmap>(getBitmapFromDrawable());
}
setup();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setup();
}
protected void setup() {
if (!mReady) {
return;
}
if (mShape == SHAPE_RECT) {
invalidate();
return;
}
Bitmap bitmap = mBitmapRef.get();
if (bitmap == null) {
bitmap = getBitmapFromDrawable();
if (bitmap == null) {
invalidate();
return;
}
mBitmapRef = new WeakReference<Bitmap>(bitmap);
}
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
int w = getWidth();
int h = getHeight();
float drawableWidth = w - mBorderWidth * 2;
float drawableHeight = h - mBorderWidth * 2;
// update shader matrix
float scale = 0, dx = 0, dy = 0;
mBitmapShaderMatrix.reset();
if (bitmapWidth * drawableHeight > drawableWidth * bitmapHeight) {
scale = drawableHeight / (float) bitmapHeight;
dx = (drawableWidth - bitmapWidth * scale) * 0.5f;
} else {
scale = drawableWidth / (float) bitmapWidth;
dy = (drawableHeight - bitmapHeight * scale) * 0.5f;
}
mBitmapShaderMatrix.setScale(scale, scale);
mBitmapShaderMatrix.postTranslate(dx + mBorderWidth, dy + mBorderWidth);
mBitmapShader.setLocalMatrix(mBitmapShaderMatrix);
invalidate();
}
protected Bitmap getBitmapFromDrawable() {
Drawable drawable = getDrawable();
if (drawable == null) {
return null;
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
try {
Bitmap bitmap = null;
if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_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 (Exception e) {
return null;
}
}
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
if (mShape == SHAPE_RECT) {
super.onDraw(canvas);
return;
}
int w = getWidth();
int h = getHeight();
float halfBorderWidth = mBorderWidth * 0.5f;
if (mShape == SHAPE_CIRCLE) {
float cx = w * 0.5f;
float cy = h * 0.5f;
float borderRadius = cx < cy ? cx : cy;
float drawableRadius = borderRadius - mBorderWidth;
borderRadius = drawableRadius + halfBorderWidth;
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setFilterBitmap(true);
mPaint.setShader(mBitmapShader);
canvas.drawCircle(cx, cy, drawableRadius, mPaint);
if (mBorderWidth > 0) {
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setColor(mBorderColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mBorderWidth);
canvas.drawCircle(cx, cy, borderRadius, mPaint);
}
} else if (mShape == SHAPE_ROUND_RECT) {
mRectF.set(0, 0, w, h);
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setFilterBitmap(true);
mPaint.setShader(mBitmapShader);
canvas.drawRoundRect(mRectF, mCornerRadius, mCornerRadius, mPaint);
}
}
@Override
public Drawable getDefault() {
return mDefaultDrawable;
}
@Override
public void setDefault(Drawable drawable) {
mDefaultDrawable = drawable;
}
@Override
public void setDefault(int resId) {
mDefaultDrawable = this.getContext().getResources().getDrawable(resId);
}
@Override
public void showDefault() {
Drawable showingDrawable = getDrawable();
if (showingDrawable != null) {
if (showingDrawable.equals(mDefaultDrawable)) {
return;
}
}
this.setImageDrawable(mDefaultDrawable);
}
@Override
public void showDefault(Drawable drawable) {
setDefault(drawable);
showDefault();
}
@Override
public void showDefault(int resId) {
setDefault(resId);
showDefault();
}
}