Created
June 6, 2016 06:27
-
-
Save vkrm26/34af4dfac34bd047480926a6952468f7 to your computer and use it in GitHub Desktop.
Custom image view which is circle in shape & also extends NetworkImageView (volley) functionality.
This file contains 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
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapShader; | |
import android.graphics.Canvas; | |
import android.graphics.ColorFilter; | |
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.net.Uri; | |
import android.support.annotation.ColorRes; | |
import android.support.annotation.DrawableRes; | |
import android.text.TextUtils; | |
import android.util.AttributeSet; | |
import android.widget.ImageView; | |
import com.android.volley.VolleyError; | |
import com.android.volley.toolbox.ImageLoader; | |
import com.truple.customer.R; | |
/** | |
* Created by vikram on 28/4/16. | |
*/ | |
public class CustomCircleCumNetworkImageView extends ImageView { | |
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 = 2; | |
private static final int DEFAULT_BORDER_WIDTH = 0; | |
private static final int DEFAULT_BORDER_COLOR = R.color.PrimaryForeground; | |
private static final boolean DEFAULT_BORDER_OVERLAY = false; | |
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 Bitmap mBitmap; | |
private BitmapShader mBitmapShader; | |
private int mBitmapWidth; | |
private int mBitmapHeight; | |
private float mDrawableRadius; | |
private float mBorderRadius; | |
private ColorFilter mColorFilter; | |
private boolean mReady; | |
private boolean mSetupPending; | |
private boolean mBorderOverlay; | |
private String mUrl; | |
private int mDefaultImageId; | |
private int mErrorImageId; | |
private ImageLoader mImageLoader; | |
private ImageLoader.ImageContainer mImageContainer; | |
public CustomCircleCumNetworkImageView(Context context) { | |
super(context); | |
init(); | |
} | |
public CustomCircleCumNetworkImageView(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
public CustomCircleCumNetworkImageView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); | |
mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, 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); | |
a.recycle(); | |
init(); | |
} | |
public void setImageUrl(String url, ImageLoader imageLoader) { | |
this.mUrl = url; | |
this.mImageLoader = imageLoader; | |
this.loadImageIfNecessary(false); | |
} | |
public void setDefaultImageResId(int defaultImage) { | |
this.mDefaultImageId = defaultImage; | |
} | |
public void setErrorImageResId(int errorImage) { | |
this.mErrorImageId = errorImage; | |
} | |
void loadImageIfNecessary(final boolean isInLayoutPass) { | |
int width = this.getWidth(); | |
int height = this.getHeight(); | |
boolean wrapWidth = false; | |
boolean wrapHeight = false; | |
if (this.getLayoutParams() != null) { | |
wrapWidth = this.getLayoutParams().width == -2; | |
wrapHeight = this.getLayoutParams().height == -2; | |
} | |
boolean isFullyWrapContent = wrapWidth && wrapHeight; | |
if (width != 0 || height != 0 || isFullyWrapContent) { | |
if (TextUtils.isEmpty(this.mUrl)) { | |
if (this.mImageContainer != null) { | |
this.mImageContainer.cancelRequest(); | |
this.mImageContainer = null; | |
} | |
this.setDefaultImageOrNull(); | |
} else { | |
if (this.mImageContainer != null && this.mImageContainer.getRequestUrl() != null) { | |
if (this.mImageContainer.getRequestUrl().equals(this.mUrl)) { | |
return; | |
} | |
this.mImageContainer.cancelRequest(); | |
this.setDefaultImageOrNull(); | |
} | |
int maxWidth = wrapWidth ? 0 : width; | |
int maxHeight = wrapHeight ? 0 : height; | |
ImageLoader.ImageContainer newContainer = this.mImageLoader.get(this.mUrl, new ImageLoader.ImageListener() { | |
public void onErrorResponse(VolleyError error) { | |
if (CustomCircleCumNetworkImageView.this.mErrorImageId != 0) { | |
CustomCircleCumNetworkImageView.this.setImageResource(CustomCircleCumNetworkImageView.this.mErrorImageId); | |
} | |
} | |
public void onResponse(final ImageLoader.ImageContainer response, boolean isImmediate) { | |
if (isImmediate && isInLayoutPass) { | |
CustomCircleCumNetworkImageView.this.post(new Runnable() { | |
public void run() { | |
onResponse(response, false); | |
} | |
}); | |
} else { | |
if (response.getBitmap() != null) { | |
CustomCircleCumNetworkImageView.this.setImageBitmap(response.getBitmap()); | |
} else if (CustomCircleCumNetworkImageView.this.mDefaultImageId != 0) { | |
CustomCircleCumNetworkImageView.this.setImageResource(CustomCircleCumNetworkImageView.this.mDefaultImageId); | |
} | |
} | |
} | |
}, maxWidth, maxHeight); | |
this.mImageContainer = newContainer; | |
} | |
} | |
} | |
private void setDefaultImageOrNull() { | |
if (this.mDefaultImageId != 0) { | |
this.setImageResource(this.mDefaultImageId); | |
} else { | |
this.setImageBitmap((Bitmap) null); | |
} | |
} | |
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { | |
super.onLayout(changed, left, top, right, bottom); | |
this.loadImageIfNecessary(true); | |
} | |
protected void onDetachedFromWindow() { | |
if (this.mImageContainer != null) { | |
this.mImageContainer.cancelRequest(); | |
this.setImageBitmap((Bitmap) null); | |
this.mImageContainer = null; | |
} | |
super.onDetachedFromWindow(); | |
} | |
protected void drawableStateChanged() { | |
super.drawableStateChanged(); | |
this.invalidate(); | |
} | |
private void init() { | |
super.setScaleType(SCALE_TYPE); | |
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 | |
public void setAdjustViewBounds(boolean adjustViewBounds) { | |
if (adjustViewBounds) { | |
throw new IllegalArgumentException("adjustViewBounds not supported"); | |
} | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
if (getDrawable() == null) { | |
return; | |
} | |
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); | |
if (mBorderWidth != 0) { | |
canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); | |
} | |
} | |
@Override | |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
super.onSizeChanged(w, h, oldw, oldh); | |
setup(); | |
} | |
public int getBorderColor() { | |
return mBorderColor; | |
} | |
public void setBorderColor(int borderColor) { | |
if (borderColor == mBorderColor) { | |
return; | |
} | |
mBorderColor = borderColor; | |
mBorderPaint.setColor(mBorderColor); | |
invalidate(); | |
} | |
public void setBorderColorResource(@ColorRes int borderColorRes) { | |
setBorderColor(getContext().getResources().getColor(borderColorRes)); | |
} | |
public int getBorderWidth() { | |
return mBorderWidth; | |
} | |
public void setBorderWidth(int borderWidth) { | |
if (borderWidth == mBorderWidth) { | |
return; | |
} | |
mBorderWidth = borderWidth; | |
setup(); | |
} | |
public boolean isBorderOverlay() { | |
return mBorderOverlay; | |
} | |
public void setBorderOverlay(boolean borderOverlay) { | |
if (borderOverlay == mBorderOverlay) { | |
return; | |
} | |
mBorderOverlay = borderOverlay; | |
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(@DrawableRes int resId) { | |
super.setImageResource(resId); | |
mBitmap = getBitmapFromDrawable(getDrawable()); | |
setup(); | |
} | |
@Override | |
public void setImageURI(Uri uri) { | |
super.setImageURI(uri); | |
mBitmap = getBitmapFromDrawable(getDrawable()); | |
setup(); | |
} | |
@Override | |
public void setColorFilter(ColorFilter cf) { | |
if (cf == mColorFilter) { | |
return; | |
} | |
mColorFilter = cf; | |
mBitmapPaint.setColorFilter(mColorFilter); | |
invalidate(); | |
} | |
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; | |
} | |
} | |
private void setup() { | |
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); | |
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()); | |
mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2); | |
mDrawableRect.set(mBorderRect); | |
if (!mBorderOverlay) { | |
mDrawableRect.inset(mBorderWidth, mBorderWidth); | |
} | |
mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); | |
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) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top); | |
mBitmapShader.setLocalMatrix(mShaderMatrix); | |
} | |
} |
This file contains 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
<?xml version="1.0" encoding="utf-8"?> | |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content"> | |
<CustomCircleCumNetworkImageView xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:id="@+id/header_icon" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_marginLeft="16dp" | |
android:layout_marginTop="16dp" | |
android:scaleType="centerCrop" | |
android:src="@drawable/user_profile" | |
app:border_color="@color/PrimaryForeground" | |
app:border_width="1dp" /> | |
</RelativeLayout> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment