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