6

How can I create a selectable circular ImageView like in the current Google+ app used for the profile pictures?

This is what I refer to:

Example

The image above is unselected and the below is selected.

I try to replicate the profile pictures 1 to 1.

My work so far:

loadedImage is the Bitmap which is displayed

mImageView.setBackground(createStateListDrawable());
mImageView.setImageBitmap(createRoundImage(loadedImage));

The used methods:

private Bitmap createRoundImage(Bitmap loadedImage) {
    Bitmap circleBitmap = Bitmap.createBitmap(loadedImage.getWidth(), loadedImage.getHeight(), Bitmap.Config.ARGB_8888);

    BitmapShader shader = new BitmapShader(loadedImage, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(shader);

    Canvas c = new Canvas(circleBitmap);
    c.drawCircle(loadedImage.getWidth() / 2, loadedImage.getHeight() / 2, loadedImage.getWidth() / 2, paint);

    return circleBitmap;
}

private StateListDrawable createStateListDrawable() {
    StateListDrawable stateListDrawable = new StateListDrawable();

    OvalShape ovalShape = new OvalShape();
    ShapeDrawable shapeDrawable = new ShapeDrawable(ovalShape);
    stateListDrawable.addState(new int[] { android.R.attr.state_pressed }, shapeDrawable);
    stateListDrawable.addState(StateSet.WILD_CARD, shapeDrawable);

    return stateListDrawable;
}

The size of the ImageView is imageSizePx and the size of the image is imageSizePx - 3. So, that means the background should overlap the image. Which doesn't work.

Leandros
  • 16,805
  • 9
  • 69
  • 108

5 Answers5

6

Really simple solution, thanks to @CommonsWare for the tips.

Size of Bitmap: imageSizePx - 3DP
Size of ImageView: imageSizePx

mImageView.setBackground(createStateListDrawable(imageSizePx));
mImageView.setImageBitmap(loadedImage);

private StateListDrawable createStateListDrawable(int size) {
    StateListDrawable stateListDrawable = new StateListDrawable();

    OvalShape ovalShape = new OvalShape();
    ovalShape.resize(size, size);
    ShapeDrawable shapeDrawable = new ShapeDrawable(ovalShape);
    shapeDrawable.getPaint().setColor(getResources().getColor(R.color.somecolor));

    stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, shapeDrawable);
    stateListDrawable.addState(new int[]{android.R.attr.state_focused}, shapeDrawable);
    stateListDrawable.addState(new int[]{}, null);

    return stateListDrawable;
}
Leandros
  • 16,805
  • 9
  • 69
  • 108
3

Assuming that by "selectable" you mean "checkable, like a CheckBox", then that could be some CompoundButton that is using a StateListDrawable with regular and checked states for the background behind the "SkillOverflow" foreground image.

You can use uiautomatorviewer to see what the actual widget is that Google+ uses.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • With selectable I mean, that I have touch feedback. I use the term selectable, because the default xml is also named `selectable_background_holo`. Sorry for confusion. – Leandros Jun 04 '13 at 16:30
  • @Leandros: Then it is probably an `ImageButton` with a custom `StateListDrawable` for the background. – CommonsWare Jun 04 '13 at 16:31
  • Most likely. The issue is, how to create the effect as in the example above? That only a stroke of the circular shape appears there and not the whole rectangle ImageButton / ImageView is highlighted. – Leandros Jun 04 '13 at 16:37
  • 1
    @Leandros: That would be the custom `StateListDrawable` for the background that I've been mentioning. What makes a button look like a button is its background, and that background is rendered with different images for different states (normal, pressed, selected, checked, etc.). – CommonsWare Jun 04 '13 at 16:38
  • Yeah, sure. Thats a good idea, before I thought of making the `ImageView` circular, but a circular `StateListDrawable` which is just about 2 pixels wider is a better idea. Now how to make a programmitically scaled `StateListDrawable`? – Leandros Jun 04 '13 at 16:47
  • @Leandros: Use a `ShapeDrawable` where possible. – CommonsWare Jun 04 '13 at 16:54
  • Ok, I created a StateListDrawable with circular shapes, but when I set my image via `setImageBitmap` the image is always the same width / height as the `ImageView`. – Leandros Jun 04 '13 at 17:38
  • @Leandros: Sounds like you need to add some padding. – CommonsWare Jun 04 '13 at 17:39
  • Yep, I did, but it doesn't worked as expected. The padding is completely ignored. I set the padding on the `ImageView` directly. – Leandros Jun 04 '13 at 17:57
  • @Leandros: You might consider opening another question, supplying your work so far, and demonstrating the flawed results that you are getting. – CommonsWare Jun 04 '13 at 17:59
  • My Edit is above in the question. – Leandros Jun 04 '13 at 18:15
2

You can make a custom View that extends ImageView. Override onDraw to clip the canvas with a circular region and draw the image on the canvas. Something like this as a starting point:

public class CircularImageView extends ImageView {
    /* constructors omitted for brevity ... */

    protected void onDraw(Canvas canvas) {
        int saveCount = canvas.save();

        // clip in a circle

        // draw image
        Drawable d = getDrawable();
        if (d != null) {
            d.draw(canvas);
        }

        // do extra drawing on canvas if pressed

        canvas.restoreToCount(saveCount);
    }
}

Take some time to get familiar with the Canvas and other 2D drawing APIs in Android.

Karakuri
  • 38,365
  • 12
  • 84
  • 104
0

I was able to achieve this effect through a custom ImageView by overriding onDraw and painting some sort of "border" whenever it detects a touch event. As a bonus, there is a selector overlay. Hopefully you may find this view helpful...

https://github.com/Pkmmte/CircularImageView

enter image description here

Pkmmte
  • 2,822
  • 1
  • 31
  • 41
0

https://github.com/hdodenhof/CircleImageView

Best library so far, super easy to integrate. It will give you border width and color option, you can change the color onClick to match your query.

Akanshi Srivastava
  • 1,160
  • 13
  • 24