package com.vansuita.materialabout.views;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.ColorFilter;
import android.graphics.Shader;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.support.annotation.ColorInt;
import android.support.annotation.DimenRes;
import android.support.annotation.DrawableRes;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewGroup;
import com.vansuita.materialabout.R;
import static com.vansuita.materialabout.views.RoundedDrawable.TAG;
/**
* Created by jrvansuita on 10/02/17.
*/
public final class CircleImageView extends AppCompatImageView {
public static final float DEFAULT_RADIUS = 0f;
public static final float DEFAULT_BORDER_WIDTH = 0f;
public static final Shader.TileMode DEFAULT_TILE_MODE = Shader.TileMode.CLAMP;
private final float[] mCornerRadii =
new float[]{DEFAULT_RADIUS, DEFAULT_RADIUS, DEFAULT_RADIUS, DEFAULT_RADIUS};
private Drawable mBackgroundDrawable;
private ColorStateList mBorderColor =
ColorStateList.valueOf(RoundedDrawable.DEFAULT_BORDER_COLOR);
private float mBorderWidth = DEFAULT_BORDER_WIDTH;
private ColorFilter mColorFilter = null;
private boolean mColorMod = false;
private Drawable mDrawable;
private boolean mHasColorFilter = false;
private boolean mIsOval = false;
private boolean mMutateBackground = false;
private int mResource;
private int mBackgroundResource;
private ScaleType mScaleType;
private Shader.TileMode mTileModeX = DEFAULT_TILE_MODE;
private Shader.TileMode mTileModeY = DEFAULT_TILE_MODE;
public CircleImageView(Context context) {
this(context, null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setBorderColor(ContextCompat.getColor(getContext(), android.R.color.white));
setBorderWidth(R.dimen.profile_picture_border);
//setCornerRadiusDimen(R.dimen.card_radius);
mutateBackground(true);
setOval(true);
}
protected void onMeasure(int width, int height) {
super.onMeasure(width, height);
if (getParent() != null) {
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();
lp.topMargin = getMeasuredHeight() / 2;
setLayoutParams(lp);
}
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
invalidate();
}
@Override
public ScaleType getScaleType() {
return mScaleType;
}
@Override
public void setScaleType(ScaleType scaleType) {
assert scaleType != null;
if (mScaleType != scaleType) {
mScaleType = scaleType;
switch (scaleType) {
case CENTER:
case CENTER_CROP:
case CENTER_INSIDE:
case FIT_CENTER:
case FIT_START:
case FIT_END:
case FIT_XY:
super.setScaleType(ScaleType.FIT_XY);
break;
default:
super.setScaleType(scaleType);
break;
}
updateDrawableAttrs();
updateBackgroundDrawableAttrs(false);
invalidate();
}
}
@Override
public void setImageDrawable(Drawable drawable) {
mResource = 0;
mDrawable = RoundedDrawable.fromDrawable(drawable);
updateDrawableAttrs();
super.setImageDrawable(mDrawable);
}
@Override
public void setImageBitmap(Bitmap bm) {
mResource = 0;
mDrawable = RoundedDrawable.fromBitmap(bm);
updateDrawableAttrs();
super.setImageDrawable(mDrawable);
}
@Override
public void setImageResource(@DrawableRes int resId) {
if (mResource != resId) {
mResource = resId;
mDrawable = resolveResource();
updateDrawableAttrs();
super.setImageDrawable(mDrawable);
}
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
setImageDrawable(getDrawable());
}
private Drawable resolveResource() {
Resources rsrc = getResources();
if (rsrc == null) {
return null;
}
Drawable d = null;
if (mResource != 0) {
try {
d = rsrc.getDrawable(mResource);
} catch (Exception e) {
mResource = 0;
}
}
return RoundedDrawable.fromDrawable(d);
}
@Override
public void setBackground(Drawable background) {
setBackgroundDrawable(background);
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
if (mBackgroundResource != resId) {
mBackgroundResource = resId;
mBackgroundDrawable = resolveBackgroundResource();
setBackgroundDrawable(mBackgroundDrawable);
}
}
@Override
public void setBackgroundColor(int color) {
mBackgroundDrawable = new ColorDrawable(color);
setBackgroundDrawable(mBackgroundDrawable);
}
private Drawable resolveBackgroundResource() {
Resources rsrc = getResources();
if (rsrc == null) {
return null;
}
Drawable d = null;
if (mBackgroundResource != 0) {
try {
d = rsrc.getDrawable(mBackgroundResource);
} catch (Exception e) {
Log.w(TAG, "Unable to find resource: " + mBackgroundResource, e);
// Don't try again.
mBackgroundResource = 0;
}
}
return RoundedDrawable.fromDrawable(d);
}
private void updateDrawableAttrs() {
updateAttrs(mDrawable, mScaleType);
}
private void updateBackgroundDrawableAttrs(boolean convert) {
if (mMutateBackground) {
if (convert) {
mBackgroundDrawable = RoundedDrawable.fromDrawable(mBackgroundDrawable);
}
updateAttrs(mBackgroundDrawable, ScaleType.FIT_XY);
}
}
@Override
public void setColorFilter(ColorFilter cf) {
if (mColorFilter != cf) {
mColorFilter = cf;
mHasColorFilter = true;
mColorMod = true;
applyColorMod();
invalidate();
}
}
private void applyColorMod() {
// Only mutate and apply when modifications have occurred. This should
// not reset the mColorMod flag, since these filters need to be
// re-applied if the Drawable is changed.
if (mDrawable != null && mColorMod) {
mDrawable = mDrawable.mutate();
if (mHasColorFilter) {
mDrawable.setColorFilter(mColorFilter);
}
// TODO: support, eventually...
//mDrawable.setXfermode(mXfermode);
//mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
}
}
private void updateAttrs(Drawable drawable, ScaleType scaleType) {
if (drawable == null) {
return;
}
if (drawable instanceof RoundedDrawable) {
((RoundedDrawable) drawable)
.setScaleType(scaleType)
.setBorderWidth(mBorderWidth)
.setBorderColor(mBorderColor)
.setOval(mIsOval)
.setTileModeX(mTileModeX)
.setTileModeY(mTileModeY);
if (mCornerRadii != null) {
((RoundedDrawable) drawable).setCornerRadius(
mCornerRadii[Corner.TOP_LEFT],
mCornerRadii[Corner.TOP_RIGHT],
mCornerRadii[Corner.BOTTOM_RIGHT],
mCornerRadii[Corner.BOTTOM_LEFT]);
}
applyColorMod();
} else if (drawable instanceof LayerDrawable) {
// loop through layers to and set drawable attrs
LayerDrawable ld = ((LayerDrawable) drawable);
for (int i = 0, layers = ld.getNumberOfLayers(); i < layers; i++) {
updateAttrs(ld.getDrawable(i), scaleType);
}
}
}
@Override
@Deprecated
public void setBackgroundDrawable(Drawable background) {
mBackgroundDrawable = background;
updateBackgroundDrawableAttrs(true);
super.setBackgroundDrawable(mBackgroundDrawable);
}
public void setBorderWidth(@DimenRes int resId) {
setBorderWidth(getResources().getDimension(resId));
}
public void setBorderWidth(float width) {
if (mBorderWidth == width) {
return;
}
mBorderWidth = width;
updateDrawableAttrs();
updateBackgroundDrawableAttrs(false);
invalidate();
}
public void setBorderColor(@ColorInt int color) {
setBorderColor(ColorStateList.valueOf(color));
}
public void setBorderColor(ColorStateList colors) {
if (mBorderColor.equals(colors)) {
return;
}
mBorderColor =
(colors != null) ? colors : ColorStateList.valueOf(RoundedDrawable.DEFAULT_BORDER_COLOR);
updateDrawableAttrs();
updateBackgroundDrawableAttrs(false);
if (mBorderWidth > 0) {
invalidate();
}
}
public void setOval(boolean oval) {
mIsOval = oval;
updateDrawableAttrs();
updateBackgroundDrawableAttrs(false);
invalidate();
}
public void mutateBackground(boolean mutate) {
if (mMutateBackground == mutate) {
return;
}
mMutateBackground = mutate;
updateBackgroundDrawableAttrs(true);
invalidate();
}
}