Android Staggered Grid

Posted by on January 13, 2014

While building the new Etsy for Android app, a key goal for our team was delivering a great user experience regardless of device. From phones to tablets, phablets and even tabphones, we wanted all Android users to have a great shopping experience without compromise.

A common element throughout our mobile apps is the “Etsy listing card”. Listing cards are usually the first point of contact users have with our sellers’ unique items, whether they’re casually browsing through categories or searching for something specific. On these screens, when a listing card is shown, we think our users should see the images without cropping.

Android Lists and Grids

A simple enough requirement but on Android things aren’t always that simple. We wanted these cards in a multi-column grid, with a column count that changes with device orientation while keeping grid position. We needed header and footer support, and scroll listeners for neat tricks like endless loading and quick return items. This wasn’t achievable using a regular old ListView or GridView.

Furthermore, both the Android ListView and GridView are not extendable in any meaningful way. A search for existing open libraries didn’t reveal any that met our requirements, including the unfinished StaggeredGridView available in the AOSP source.

Considering all of these things we committed to building an Android staggered grid view. The result is a UI component that is built on top of the existing Android AbsListView source for stability, but supports multiple columns of varying row sizes and more.

Android Trending - Devices

How it Works

The StaggeredGridView works much like the existing Android ListView or GridView. The example below shows how to add the view to your XML layout, specifying the margin between items and the number of columns in each orientation.

<com.etsy.android.grid.StaggeredGridView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/grid_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:item_margin="8dp"
    app:column_count_portrait="2"
    app:column_count_landscape="3" />

You can of course set the layout margin and padding as you would any other view.

To show items in the grid create any regular old ListAdapter and assign it to the grid. Then there’s one last step. You need to ensure that the ListAdapter’s views maintain their aspect ratio. When column widths adjust on rotation, each item’s height should respond.

How do you do this? The AndroidStaggeredGrid includes a couple of utility classes including the DynamicHeightImageView which you can use in your adapter. This custom ImageView overrides onMeasure() and ensures the measured height is relative to the width based on the set ratio. Alternatively, you can implement any similar custom view or layout with the same measurement logic.

public void setHeightRatio(double ratio) {
    if (ratio != mHeightRatio) {
        mHeightRatio = ratio;
        requestLayout();
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (mHeightRatio > 0.0) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = (int) (width * mHeightRatio);
        setMeasuredDimension(width, height);
    }
    else {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

And that’s it. The DynamicHeightImageView will maintain the aspect ratio of your items and the grid will take care of recycling views in the same manner as a ListView. You can check out the GitHub project for more details on how it’s used including a sample project.

But There’s More

Unlike the GridView, you can add header and footer views to the StaggeredGridView. You can also apply internal padding to the grid that doesn’t affect the header and footer views. An example view using these options is shown below. On our search results screen we use a full width header and add a little extra horizontal grid padding for 10 inch tablets.

Android Search

Into the Real World

During the development process we fine-tuned the grid’s performance using a variety of real world Android devices available in the Etsy Device Lab. When we released the new Etsy for Android app at the end of November, the AndroidStaggeredGrid was used throughout. Post launch we monitored and fixed some lingering bugs found with the aid of the awesome crash reporting tool Crashlytics.

We decided to open source the AndroidStaggeredGrid: a robust, well tested and real world UI component for the Android community to use. It’s available on GitHub or via Maven, and we are accepting pull requests.

Finally, a friendly reminder that the bright folks at Etsy mobile are hiring.

You can follow Deniz on Twitter at @denizmveli.

Posted by on January 13, 2014
Category: mobile Tags: ,

4 Comments

This is amazing! I tried to create a similar view last year, but I quickly ran into the early problems you mentioned. Can’t wait to try this out.

The Etsy app has a Staggered Grid layout that also has touch feedback, but the library has that listed as one of the missing features. How do you guys handle that in the Etsy app? Would like to have proper touch feedback on my items.

Hi

I am happy with this android grid. i am trying with it and its work.

I have 1 question … when i add header and call click event the position return header not from the grid .

i would like to handle header with other click events not with grid onitem click

thanks

wow , amazing demo.
Thank u very much.