0

I'm searching for a library that could help me make my cricular image view's like in Facebook Messenger (with z blue Messenger icon or grey Facebook icon). How they came up with it? Can it be done with Glide? If not, with what then?

jean d'arme
  • 4,033
  • 6
  • 35
  • 70
  • 1
    Possible duplicate of [How do rounded image with Glide library?](http://stackoverflow.com/questions/25278821/how-do-rounded-image-with-glide-library) – TWiStErRob Oct 01 '15 at 09:44

3 Answers3

2

Using CircleImageView/CircularImageView/RoundedImageView is not advised, we have many people reporting issues with them mostly because they hack the Bitmap out of the Drawable which is incompatible with the most basic feature of Glide: .crossFade(), also GIF animations may likely break with them.

The correct Glide way is to use Transformations, you can find a good enough one here: https://stackoverflow.com/a/25806229/253468

Glide 4.0 will have a built-in CircleCrop transformation.

Overlay icon

The overlay icon can be also added with a transformation:

// .transform(new CircleTransform(context)), new StatusTransform(context, user.getStatus()))
public static class StatusTransform extends BitmapTransformation {
    private final Status status;
    public StatusTransform(Context context, Status status) {
        super(context);
        this.status = status;
    }

    @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        int w = toTransform.getWidth(), h = toTransform.getHeight();
        Bitmap result = pool.get(w, h, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        }
        Canvas canvas = new Canvas(result);
        canvas.drawBitmap(toTransform);
        switch(status) {
            case Online:
                canvas.draw*(online graphics);
                break;
            case Offline:
                canvas.draw*(offline graphics);
                break;
        }
        return result;
    }

    @Override public String getId() {
        return getClass().getName() + status;
    }
}

or simply have two ImageViews:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="@dimen/user_profile_size"
    android:layout_height="@dimen/user_profile_size"
    >
    <ImageView
        android:id="@id/user_profile"
        android:layout_width="@dimen/user_profile_size"
        android:layout_height="@dimen/user_profile_size"
        />
    <ImageView
        android:id="@id/user_status"
        android:layout_width="@dimen/user_status_size"
        android:layout_height="@dimen/user_status_size"
        android:layout_gravity="bottom|end"
        />
</FrameLayout>

Both have pros and contras: Transformation results can be cached, so if you have 3 statuses Glide will store each user's profile image 3 times overlayed with a little icon, so it probably will be applied only once and then it's just a matter of decoding the cached PNG (not JPEG, because circle forces transparency). With two ImageViews you have to have two Glide load lines (or a Glide and a setImageResource), it may be a little slower to draw and layout. So you can trade processor time to disk space with the two approaches. With the ImageView approach you can also animate the transitions between status changes and have the status always show, even when the profile image is loading slowly because of bad network.

In case of the Transformation if the code of the transform method changes, you'll need to invalidate the cache, which can be achieved by:

.signature(ApplicationVersionSignature.obatain(context)) // every release
// or
.signature(new StringSignature(String.valueOf( System.currentTimeMillies() / (10 * 60 * 1000) ))) // every 10 minutes

Alternatively this invalidation can be built into the getId() method somehow.

Community
  • 1
  • 1
TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
  • I'm using that one :) – jean d'arme Oct 01 '15 at 11:40
  • Still, it does not resolve my problem. Btw, when Glide 4.0 comes up? – jean d'arme Oct 01 '15 at 11:43
  • I'm sorry, somehow I missed that really bad :) There's no set date yet, I think it's still in alpha. – TWiStErRob Oct 01 '15 at 11:59
  • That's nice :) I must try this - it will be for static purposes so no status changing need. Can I ask You for example of `canvas.draw*(online graphics)` ? – jean d'arme Oct 01 '15 at 14:00
  • It's not actual code, I just sketched this here in the editor. I meant stuff like: `drawBitmap`, `drawCircle`, `drawText`, `drawRoundRect`. Or: `Drawable d = context.getDrawable(R.drawable.ic_status_x); int s = context.getResources().getDimensionPixelSize(R.dimen.user_status_size); d.setBounds(w - s, h - s, w, h); d.draw(canvas);` – TWiStErRob Oct 01 '15 at 14:11
  • Thanks a lot :) I'm still in my infancy with coding. – jean d'arme Oct 01 '15 at 14:35
  • Great library and fastest one. – Eftekhari Feb 14 '16 at 12:19
  • Added a transform to round corners, but now GIFs are always static. Short of creating a new gif at runtime I don't see how a transform is better than a circle view. – Grzegorz Adam Hankiewicz Oct 14 '16 at 11:05
  • @GrzegorzAdamHankiewicz transformations applied to GIF do each frame separately, so it should work. Are you using `asBitmap` by any chance? If you want more help, please open an issue on GitHub so we can have a proper conversation. – TWiStErRob Oct 14 '16 at 16:29
  • @TWiStErRob found the problem, I was extending `BitmapTransformation` instead of implementing `Transformation`. Looking at https://github.com/wasabeef/glide-transformations helped. – Grzegorz Adam Hankiewicz Oct 15 '16 at 19:26
0

1.I would suggest you to checkout Image Management Library by Facebook that is Fresco that is pretty awesome and mature as compared to other Image Loading Library.

2.Fresco has SimpleDraweeView as custom image view which supports Rounded Corners and Circles link and supports Animated(.gif, .webp) as well as Normal Images(.jpg, .png).

3.Fresco handles all the things caching of images with 3 Tier architecture ( BITMAP_MEMORY_CACHE, ENCODED_MEMORY_CACHE and DISK_CACHE). It also reduces OOM(Out Of Memory) issues. When image in a view goes out of screen it automatically recycles the bitmap, hence releasing the memory.

Vipul Asri
  • 8,903
  • 3
  • 46
  • 71
-1

if your target is only have a CircleImage give a shot at this:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ImageView;

public class RoundedImageView extends ImageView
{
    public RoundedImageView(Context context)
    {
        super(context);
    }

    public RoundedImageView(Context context, @Nullable AttributeSet attrs)
    {
        super(context, attrs);
    }

    public RoundedImageView(Context context, @Nullable AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public RoundedImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public static Bitmap getCroppedBitmap(Bitmap bmp, int radius)
    {
        Bitmap sbmp;

        if (bmp.getWidth() != radius || bmp.getHeight() != radius)
        {
            float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
            float factor = smallest / radius;
            sbmp = Bitmap.createScaledBitmap(bmp, (int) (bmp.getWidth() / factor), (int) (bmp.getHeight() / factor), false);
        }
        else
        {
            sbmp = bmp;
        }

        Bitmap output = Bitmap.createBitmap(radius, radius,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xffa19774;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, radius, radius);

        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);
        paint.setDither(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(Color.parseColor("#BAB399"));
        canvas.drawCircle(radius / 2 + 0.7f,
                radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(sbmp, rect, rect, paint);

        return output;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        Drawable drawable = getDrawable();

        if (drawable == null)
        {
            return;
        }

        if (getWidth() == 0 || getHeight() == 0)
        {
            return;
        }
        Bitmap b = ((BitmapDrawable) drawable).getBitmap();
        Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

        int w = getWidth(), h = getHeight();

        Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
        canvas.drawBitmap(roundBitmap, 0, 0, null);
    }
}

and in your layout you can use this:

<mypkg.example.RoundedImageView
    android:id="@+id/roundimg"
    android:layout_width="54dp"
    android:layout_height="54dp"
    android:layout_gravity="center"/>

and programmatically you can set a letter..

Rect textBounds = new Rect();
String text = "N"
Bitmap bitmap = Bitmap.createBitmap(imageView.getLayoutParams().width, imageView.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.DKGRAY);
TextPaint p = new TextPaint();
p.setColor(Color.WHITE);
p.setTextSize(imageView.getLayoutParams().height / 2);
p.setAntiAlias(true);
p.setTextAlign(Paint.Align.LEFT);
p.getTextBounds(text, 0, text.length(), textBounds);

int cx = imageView.getLayoutParams().width / 2;
int cy = imageView.getLayoutParams().height / 2;
canvas.drawText(text, cx - textBounds.exactCenterX(), cy - textBounds.exactCenterY(), p);

imageView.setImageBitmap(bitmap);

or an image ..

// image grabbed from an input stream
Bitmap photo = BitmapFactory.decodeStream(inputStream);
imageView.setImageBitmap(photo);

is this useful? more infos and credits here How to create a circular ImageView in Android?

Community
  • 1
  • 1
Davide
  • 126
  • 8