Rounded image view in Android

Image for post
Image for post
“Interior of San Francisco Museum of Modern Art architecture in circular white room with walkway” by Sebastien Gabriel on Unsplash

The common use-case is like this: you need to get an image from some server, resize and cache it (you’re using Picasso for this, aren’t you?), make corners rounded (ok, this is not the most popular use-case, but it’s what this article is about) and load it into view. So, how can we make rounded corners?

As usual, we have several ways to achieve this in Android.

Option #1. Overlay

Some desperate person can offer you to place your image view inside FrameLayout, add another image above it with a transparent body and solid corners and… you’re done. Do I need to tell you that this is very bad practice, and you should never do that?

Option #2. clipPath

Rather a simple method. You just need to create a custom view with an overridden onDraw method of ImageView and use method clipPath on canvas instance there. The problem is that path clipping doesn’t support anti-aliasing, so your image will have ugly sharp edges.

Option #3. BitmapShader

A way better option is to use a Paint with BitmapShader. It allows filling the rounded rectangle with a texture, not only with a simple color. Luckily we have RoundedBitmapDrawable within support library that uses this technique, we just need to combine image loading with Picasso and transforming it into one view, which leads us to option #4:

Option #4. RoundedBitmapDrawable

So, let’s start. The code is written in Kotlin, because… well, why would you write in Java when you have Kotlin?

As we will use our view with Picasso only, we don’t even need to inherit it from ImageView, simple View would be enough:

class RoundedImageView(
context: Context,
attributeSet: AttributeSet?
) : View(context, attributeSet), Target {
constructor(context: Context) : this(context, null)
}

In order to allow Picasso to load an image into our view, it should implement Target interface, which includes 3 methods: onPrepareLoad, onBitmapFailed and onBitmapLoaded. All the magic is done in onBitmapLoaded method:

override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
val roundedDrawable = RoundedBitmapDrawableFactory.create(resources, bitmap)
roundedDrawable.cornerRadius = dip(DEFAULT_RADIUS).toFloat()
drawable = roundedDrawable
}

Finally, we need to draw our Drawable in onDraw method (sounds very reasonable, isn’t it?):

override fun onDraw(canvas: Canvas?) {
drawable?.setBounds(0, 0, width, height)
drawable?.draw(canvas)
}

So the complete code together with helper method for loading image by URL string is here:

That’s all! If you have any questions or notes, feel free to leave a comment.

Head of Applications @ Mews

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store