com.tr4android.support.extension.widget.CircleImageView.java Source code

Java tutorial

Introduction

Here is the source code for com.tr4android.support.extension.widget.CircleImageView.java

Source

/*
 * Copyright (C) 2015 Thomas Robert Altstidl
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tr4android.support.extension.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.support.v7.widget.AppCompatDrawableManager;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.util.Log;

import com.tr4android.appcompat.extension.R;
import com.tr4android.support.extension.drawable.PlaceholderDrawable;
import com.tr4android.support.extension.utils.ThemeUtils;

/**
 * A supercharged ImageView that displays images as circles and creates placeholder images
 */
public class CircleImageView extends AppCompatImageView {
    private static final String LOG_TAG = "CircleImageView";

    // whether the image should be clipped to a circle
    private boolean mIsCircleImageEnabled = true;

    // whether an image drawable is being resolved
    private boolean mIsResolvingDrawable;

    // the placeholder drawable used for drawing the placeholder
    private PlaceholderDrawable mPlaceholderDrawable;

    // default color for circle
    private int mPlaceholderCircleDefaultColor;

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

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyleAttr, 0);
        mIsCircleImageEnabled = a.getBoolean(R.styleable.CircleImageView_circleImageEnabled, true);
        mPlaceholderCircleDefaultColor = a.getColor(R.styleable.CircleImageView_placeholderCircleColor,
                ThemeUtils.getThemeAttrColor(getContext(), R.attr.colorAccent));
        int textColorPrimaryInverse = ThemeUtils.getThemeAttrColor(getContext(),
                android.R.attr.textColorPrimaryInverse);
        int mPlaceholderTextSize = a.getDimensionPixelSize(R.styleable.CircleImageView_placeholderTextSize,
                getResources().getDimensionPixelSize(R.dimen.defaultPlaceholderTextSize));
        int mPlaceholderTextColor = a.getColor(R.styleable.CircleImageView_placeholderTextColor,
                textColorPrimaryInverse);
        int mPlaceholderImageSize = a.getDimensionPixelSize(R.styleable.CircleImageView_placeholderIconSize,
                getResources().getDimensionPixelSize(R.dimen.defaultPlaceholderImageSize));
        int mPlaceholderImageColor = a.getColor(R.styleable.CircleImageView_placeholderIconColor,
                textColorPrimaryInverse);
        a.recycle();

        mPlaceholderDrawable = new PlaceholderDrawable(mPlaceholderTextSize, mPlaceholderTextColor,
                mPlaceholderImageSize, mPlaceholderImageColor);
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        if (mIsCircleImageEnabled) {
            setImageDrawable(getCircleBitmapDrawable(getContext(), bm));
        } else {
            super.setImageBitmap(bm);
        }
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        if (mIsCircleImageEnabled && drawable != null && !(drawable instanceof RoundedBitmapDrawable)
                && !(drawable instanceof PlaceholderDrawable)) {
            setImageDrawable(getCircleBitmapDrawable(getContext(), getBitmapFromDrawable(drawable)));
        } else {
            super.setImageDrawable(drawable);
        }
    }

    @Override
    public void setImageResource(@DrawableRes int resId) {
        if (mIsCircleImageEnabled) {
            mIsResolvingDrawable = true;
            super.setImageResource(resId);
            mIsResolvingDrawable = false;
            setImageDrawable(getCircleBitmapDrawable(getContext(), getBitmapFromDrawable(getDrawable())));
        } else {
            super.setImageResource(resId);
        }
    }

    @Override
    public void setImageURI(Uri uri) {
        if (mIsCircleImageEnabled) {
            mIsResolvingDrawable = true;
            super.setImageURI(uri);
            mIsResolvingDrawable = false;
            setImageDrawable(getCircleBitmapDrawable(getContext(), getBitmapFromDrawable(getDrawable())));
        } else {
            super.setImageURI(uri);
        }
    }

    /**
     * Set whether the image should be transformed to a circle or not
     *
     * @param enabled pass true to enable, false to disable circular images
     */
    public void setCircleImageEnabled(boolean enabled) {
        mIsCircleImageEnabled = enabled;
    }

    /**
     * Check whether the image is transformed to a circle or not
     *
     * @return true if circular images are enabled, false if they are disabled
     */
    public boolean isCircleImageEnabled() {
        return mIsCircleImageEnabled;
    }

    /**
     * Set a placeholder with a text. This will use the default circle color.
     * <p/>
     * Note: This usually should be the first letter of a name. You can use the helper {@link #retrieveLetter(String)}
     * to extract the first letter of a given {@link String}.
     *
     * @param placeholderText Placeholder text to display in the middle of the circle
     */
    public void setPlaceholder(String placeholderText) {
        setPlaceholder(placeholderText, mPlaceholderCircleDefaultColor);
    }

    /**
     * Set a placeholder with a text and circle color.
     * <p/>
     * Note: This usually should be the first letter of a name. You can use the helper {@link #retrieveLetter(String)}
     * to extract the first letter of a given {@link String}.
     *
     * @param placeholderText Placeholder text to display in the middle of the circle
     * @param circleColor     Color to use for the circle
     */
    public void setPlaceholder(String placeholderText, @ColorInt int circleColor) {
        mPlaceholderDrawable.setPlaceholder(placeholderText, circleColor);
        setImageDrawable(mPlaceholderDrawable);
    }

    /**
     * Set a placeholder with an image. This will use the default circle color.
     *
     * @param resId The resource id of the placeholder drawable
     */
    public void setPlaceholder(@DrawableRes int resId) {
        setPlaceholder(AppCompatDrawableManager.get().getDrawable(getContext(), resId),
                mPlaceholderCircleDefaultColor);
    }

    /**
     * Set a placeholder with an image. This will use the default circle color.
     *
     * @param drawable The placeholder drawable
     */
    public void setPlaceholder(Drawable drawable) {
        setPlaceholder(drawable, mPlaceholderCircleDefaultColor);
    }

    /**
     * Set a placeholder with an image and circle color.
     *
     * @param resId       The resource id of the placeholder drawable
     * @param circleColor Color to use for the circle
     */
    public void setPlaceholder(@DrawableRes int resId, @ColorInt int circleColor) {
        setPlaceholder(AppCompatDrawableManager.get().getDrawable(getContext(), resId), circleColor);
    }

    /**
     * Set a placeholder with an image and circle color.
     *
     * @param drawable    The placeholder drawable
     * @param circleColor Color to use for the circle
     */
    public void setPlaceholder(Drawable drawable, @ColorInt int circleColor) {
        mPlaceholderDrawable.setPlaceholder(drawable, circleColor);
        setImageDrawable(mPlaceholderDrawable);
    }

    /**
     * Small Helper for extracting the first letter of a {@link String}.
     *
     * @param text the full text representing e.g. a name
     * @return the first letter uppercase
     */
    public static String retrieveLetter(String text) {
        return String.valueOf(text.charAt(0)).toUpperCase();
    }

    @Override
    public void onDraw(Canvas canvas) {
        if (mIsResolvingDrawable)
            return;
        super.onDraw(canvas);
    }

    /**
     * Helper for creating a circle bitmap drawable using the {@link android.support.v4.graphics.drawable.RoundedBitmapDrawable}
     *
     * @param bitmap The bitmap which should be converted to a circle bitmap drawable
     * @return the {@link android.support.v4.graphics.drawable.RoundedBitmapDrawable} containing the bitmap
     */
    public static RoundedBitmapDrawable getCircleBitmapDrawable(Context context, Bitmap bitmap) {
        RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(), bitmap);
        drawable.setCornerRadius(Math.max(bitmap.getWidth() / 2, bitmap.getHeight() / 2));
        drawable.setAntiAlias(true);
        return drawable;
    }

    /**
     * Helper for creating a bitmap from a drawable
     *
     * @param drawable The drawable which should be converted to a bitmap
     * @return the bitmap containing the drawable
     */
    public static Bitmap getBitmapFromDrawable(Drawable drawable) {
        if (drawable == null)
            return null;
        if (drawable instanceof BitmapDrawable) {
            Log.w(LOG_TAG, "For better performance consider using setImageBitmap() instead!");
            return ((BitmapDrawable) drawable).getBitmap();
        } else {
            Bitmap bitmap = Bitmap.createBitmap(Math.max(2, drawable.getIntrinsicWidth()),
                    Math.max(2, drawable.getIntrinsicHeight()), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        }
    }
}