ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

A guide for Android ImageView ScaleType and adjustViewBounds

--

For a long time we’ve had this bug in our Live TV section where some of the channel logos were squashed. I finally decided that it was time to fix it.

SkySports main event and SkySports football logos are squashed

The bug

In the image above you can clearly see the SkySports main event logo is squashed, the same happens with SkySports football although is less noticeable and finally SkySports Premier League is showing just fine. The question is why?

Below is part of the code from our ImageView. We are trying to say that we want to resize our logos to always have an 18dp height and then use whatever width they need. We also had set scaleType to fitXY.

android:layout_width="wrap_content"
android:layout_height="18dp"
android:scaleType="fitXY"

Let’s have a look at what fitXY does.

In theory this doesn’t look really bad, we are going to have our fixed height and then it’s going to scale our image filling the width. But we know this doesn’t really work so let’s dig in a little bit more and see what Matrix.ScaleToFit.FILL does.

The image is going to scale X and Y independently which may change the aspect ratio of it. That is exactly what’s happening, the aspect ratio of the image is changing and stretching it.

adjustViewBounds to the rescue

Fortunately there is a really simple way to preserve the aspect ratio of the image while keeping control of one dimension (in our case the height). When we set adjustViewBounds to true we are telling the ImageView (not the drawable) to adjust its bounds to preserve the aspect ratio of its drawable.

android:layout_width="wrap_content"
android:layout_height="18dp"
android:scaleType="fitXY"
android:adjustViewBounds="true"

By adding adjustViewBounds and leaving the layout_with as wrap_content we are keeping the aspect ratio of the image while keeping the height to 18dp but letting the width change accordingly, so we are still able to control the size of the image (kind of) and maintaining the aspect ratio at the same time.

All the logos are scaled and keep the aspect ratio

This was a really simple fix and actually we just had to do it in our tablet layouts because our phone layout already had adjustViewBounds set to true.

I could have left it like this and move on but I thought that it would be interesting to check what would happen if I were to use all the different types of scaling that we have available. So here are the results.

Experimenting with scaleType

We already know what happens when we use fitXY so let’s have a look at the other types that we can use. For the following experiments I will be using adjustViewBounds first and then disabling it to see how it affects the rendering of the images.

adjustViewBounds=true

Using adjustViewBounds

Here we are centering the image without any scaling and because we are keeping the aspect ratio of the ImageView with adjustViewBounds the size of the ImageView (not the image) keeps the aspect ratio of the image.

adjustViewBounds=false

Without adjustViewBounds

In this case we are not using adjustViewBounds so the ImageView is not keeping the aspect ratio and that’s why the width has massively increased. The image is still centered.

adjustViewBounds=true and adjustViewBounds=false

In this case having adjustViewBounds or not doesn’t make a difference. The reason is because the image is scaled uniformly so it maintains the aspect ratio but because the image will be equal or larger than the ImageView the width of the ImageView is going to be larger in both cases. This result is also the same as using center without adjustViewBounds.

Same result with and without adjustViewBounds

adjustViewBounds=true

For this example I have changed the background color of the ImageView to purple. The image is scaled uniformly and maintains the aspect ratio, in this case because the image will be equal or less than the ImageView it gets centered in it. Also the height is maintained since we are using adjustViewBounds.

Using adjustViewBounds

adjustViewBounds=false

By removing adjustViewBounds we are not longer bounding the height of the ImageView with the image so the image is scaled down to preserve the aspect ratio.

Without adjustViewBounds

Fit center computes a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The result is centered inside dst.

adjustViewBounds=true

This works well in our case because we are setting the height along with adjustViewBounds so the image is kept centered and the aspect ratio maintained.

Using adjustViewBounds

adjustViewBounds=false

When we remove adjustViewBounds we have the same problem that we had before, it looks similar just because we are setting the height but the computation is different. Here we scale the image keeping the aspect ratio, making sure it fits in our ImageView and then the image is centered. I’ve changed again the background color to see the difference.

Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. END aligns the result to the right and bottom edges of dst.

adjustViewBounds=true

The result is the same as with fit_center. Because we use adjustViewBounds and we set the height, the ImageView has the same aspect ratio as the image and the image is perfectly aligned.

adjustViewBounds=false

In this case the difference with fit_center is the image is now being aligned to the right and bottom of the ImageView.

Without adjustViewBounds

Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. START aligns the result to the left and top edges of dst.

adjustViewBounds=true

Pretty much the same case as fit_center and fit_end.

adjustViewBounds=false

Without adjustViewBounds

No surprises here, the difference is the image being aligned to the left and top of the ImageView.

I’m not going to show what the result is when you apply matrix, suffice to say that you should use matrix as the scaleType when you want to use a specific matrix to scale your image. You can use the code below to assign a new matrix.

imageView.imageMatrix = yourMatrix

I hope you now understand better what the different scale types do to your images and how adjustViewBounds can help you to achieve the correct behaviour. Did you already know how to use them, or do you have any questions about it? Feel free to contact me ;)

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Marcos Holgado

Senior Android Developer at DuckDuckGo. Speaker, Kotlin lover and I also fly planes. www.marcosholgado.com

Responses (3)

Write a response