Aspect Ratio in Staggered LayoutManager using Constraint Layout

Hello Developers !!! Today we are going to learn an efficient way to maintain the aspect ratio of our View in Staggered Layout using Constraint Layout. We will take the example of Pinterest app design. This article assumes that you already have basic knowledge of LayoutManager and ConstraintLayout if not then I recommend reading the following link before going further.

This is our goal to design like the Pinterest layout. For this, we need a StaggeredGridLayoutManager in RecycleView.


What is StaggeredGridLayoutManager ?

As per doc, Staggered layout manager is a LayoutManager that lays out children in a staggered grid formation. It supports horizontal & vertical layout as well as an ability to layout children in reverse.

In Staggered Layout, the Aspect Ratio of each item in a list might be different and it will get more complex when we try to load an image from a URL. So while loading image from URL we don’t know the exact aspect ratio of the image. So what we do is, Keep the image width as match_parent and height as wrap_content in our row layout, so whenever the image is loaded, it will automatically wrap its height as per the image width.

The Problem ?

We know that some time internet connection might be very slow which takes a lot of time to load the image, So in the normal scenario, we use a placeholder image while loading the actual image to make the user experience better.

But in Staggered Layout as we don’t know the aspect ratio of image until its fully loaded and also our placeholder aspect ratio might be different than the actual image ,So Initially while loading images in list we see all the item in placeholder aspect ratio and when the actual image is loaded completely its starts to set the actual image with its own aspect ratio, This makes the user experience bad because when user scrolls the list, then the item changes its height/width very frequently.

Don’t need to worry, we can now solve this using constraint layout aspect ratio feature. But first, you need to know how aspect ratios work in Constraint Layout.

Aspect Ratio in Constraint Layout

Aspect Ratios let you accomplish roughly the same thing as a PercentFrameLayout, i.e. restrict a View to a set width to height ratio, without the overhead of the additional ViewGroup in your hierarchy.

Setting a ratio on a view

To set a ratio for any view inside a ConstraintLayout:

  1. Make sure at least one of the size constraints is dynamic, i.e. not “Fixed” and not “Wrap Content”.
  2. Click the “Toggle aspect ratio constraint” that appears in the top left corner of the box.
  3. Input the desired aspect ratio in width:height format, for example: 16:9

For More Detail on Constraint Layout you can read this great article

https://medium.com/google-developers/building-interfaces-with-constraintlayout-3958fa38a9f7

The Solution

As we’ve discussed the problem above, one solution that developer came across is to fetch the height/width of an image directly from the back-end API and set the placeholder ratio fetched from the back-end API, which will lead to a smooth user experience when the user scrolls the list.

But before the constraint layout came into the picture developers used to do a lot of work to set the height/width on image manually.

For that first, we need to calculate the image width based on device size and span count than convert that px value to dp and then set the height/width of image programmatically on onBindViewHolder() and while calculating the width of the view you need to also consider the padding.

This was a lot of manual work but we have constraint layout now we can directly set the ratio on image view and the constraint layout will take care of all that.

Let see an example

First we will build our row_poster.xml

In above layout, we have set the ImageView width/height to 0dp which is match_constraint in Constraint layout which means its behave as match_parent.

By default, we kept the app:layout_constraintDimensionRatio="1:1" which means our Image will be square by default.

Now here we have MoviePoster Model.

class MoviePoster(var name: String,
                  var imageUrl: String,
                  var width: Int,
                  var height: Int)

which has width and height of image URL fetched from web services.

By default we kept the app:layout_constraintDimensionRatio="1:1" which means our Image will be square.Now, will set the aspect ratio of each image programmatically.

This is how we set the aspect ratio of an image using constraint layout, We will create a global ContraintSet() object and use it onBindViewHolder() like this

class MoviePosterAdapter : RecyclerView.Adapter<MoviePosterAdapter.ViewHolder>() {

private val set = ConstraintSet()

override fun onBindViewHolder(holder: ViewHolder, position: Int)         {
    val poster = mMoviePosters[position]

    holder.mMovieName.text = poster.name

    Glide.with(holder.itemView.context)
                .setDefaultRequestOptions(requestOptions)
                .load(poster.imageUrl)
                .into(holder.mImgPoster)
    val ratio =String.format("%d:%d", poster.width,poster.height)
    set.clone(holder.mConstraintLayout)
    set.setDimensionRatio(holder.mImgPoster.id, ratio)
    set.applyTo(holder.mConstraintLayout)
}

We will clone the current constraint of the view in ContraintSet() object and then will set the dimension ratio in “width: height” format and provide the id of the view on which we want to set this ratio i.e in our scenario is ImageView’s id.

And last we apply the changed constraint from set object to our Constraintlayout.

That’s it :)…That’s all we need to do…Constraint Layout will manage all the stuff.

You can checkout this example on GitHub. Since the Kotlin is our new java this example is written in Kotlin.

https://medium.com/google-developers/building-interfaces-with-constraintlayout-3958fa38a9f7

Thank you !!!

If you find this article helpful. Please like,share and clap. If you have any quires or suggestions, feel free to hit me on Twitter.

Leave a reply:

Your email address will not be published.

Site Footer

Sliding Sidebar

About Me

About Me

Software Engineer, Google Developer Expert in Flutter & Open Source enthusiast, Google Certified Android Developer #AndroidDev #Kotlin #FlutterDev #flutterio

Social Profiles

Tweets

Instagram Slider

  • Just Fun
  • I really had amazing time at GDESummit2019  Learn a
  • Building complex app is not easy If you are looking
  • Glimpse of my talk Build reactive architecture in Flutter in
  • Its a wrap Devfest19 Delhi done Next stop  Devfest19
  • Glimpse of my talk Build Android UI in Flutter at
  • If you are AndroidDev looking to apply your existing android
  • Achievements Unlocked!! I am proudhappy and excited to announce that
  • happyindependenceday