Android Tip: Staggered Grid view by RecyclerView

    RecyclerView is a flexible widget provided in Material Design technology. With it, we can build both grid and list layouts (read this post). Because of it's new structure (not based on AdapterView), beginners may feel difficult to approach but when get used to it, Android developers will realize it is an excellent alternative for GridView and ListView.
    I also had a post about making "auto-column" grid view by RecyclerView here and in this tip, I will present the way to make a staggered grid layout by this widget after a few simple steps.

Import dependencies

    Firstly, importing RecyclerView and CardView dependencies (I used CardViews as grid view item) to your application build.gradle:
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:cardview-v7:24.0.0'
    compile 'com.android.support:recyclerview-v7:24.0.0'
    compile 'com.android.support:appcompat-v7:24.0.0'
}

Building RecyclerView adapter

    Make a subclass of RecyclerView.ViewHolder is required in building a RecyclerView adapter:
public class BookViewHolder extends RecyclerView.ViewHolder {

        private TextView bookName;
        private TextView author;
        private View container;

        public BookViewHolder(View itemView) {
            super(itemView);

            bookName = (TextView) itemView.findViewById(R.id.book_name);
            author = (TextView) itemView.findViewById(R.id.author);
            container = itemView.findViewById(R.id.card_view);
        }
    }
    And our adapter class is extended from RecyclerView.Adapter, we also put BookViewHolder class as an inner class here:
BookRecyclerViewAdapter.java
package info.devexchanges.staggeredrecyclerview;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

public class BookRecyclerViewAdapter extends RecyclerView.Adapter {

    private List bookList;
    private Context context;

    public BookRecyclerViewAdapter(Context context, List itemList) {
        this.bookList = itemList;
        this.context = context;
    }

    @Override
    public BookViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_grid, null, false);
        return new BookViewHolder(layoutView);
    }

    @Override
    public void onBindViewHolder(BookViewHolder holder, final int position) {
        holder.bookName.setText(bookList.get(position).getName());
        holder.author.setText(bookList.get(position).getAuthor());

        holder.container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "You clicked at position: " + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return this.bookList.size();
    }

    public class BookViewHolder extends RecyclerView.ViewHolder {

        private TextView bookName;
        private TextView author;
        private View container;

        public BookViewHolder(View itemView) {
            super(itemView);

            bookName = (TextView) itemView.findViewById(R.id.book_name);
            author = (TextView) itemView.findViewById(R.id.author);
            container = itemView.findViewById(R.id.card_view);
        }
    }
}
    And this is layout (xml file) for each grid view item:
item_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="16dp"
    card_view:cardCornerRadius="8dp"
    card_view:cardUseCompatPadding="true">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/book_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="10dp" />

        <TextView
            android:id="@+id/author"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_below="@+id/book_name"
            android:background="#1976D2"
            android:gravity="center_horizontal"
            android:paddingBottom="8dp"
            android:paddingTop="8dp"
            android:text="@string/app_name"
            android:textColor="#ffffff"
            android:textSize="13sp" />

    </RelativeLayout>

</android.support.v7.widget.CardView>

Design staggered grid layout in activity

    As we known, RecyclerView always has a LayoutManager and in order to build a staggered grid view, we must use StaggeredGridLayoutManager for it.
    This is code for our activity:
MainActivity.java
package info.devexchanges.staggeredrecyclerview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;

import java.util.ArrayList;
import java.util.List;


public class MainActivity extends AppCompatActivity {

    private StaggeredGridLayoutManager layoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);

        layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        List<Book> bookList = getListItemData();

        BookRecyclerViewAdapter adapter = new BookRecyclerViewAdapter(MainActivity.this, bookList);
        recyclerView.setAdapter(adapter);
    }

    private List<Book> getListItemData(){

        List<Book> listViewItems = new ArrayList<>();
        listViewItems.add(new Book("1984", "George Orwell"));
        listViewItems.add(new Book("Lão Hạc", "Nam Cao"));
        listViewItems.add(new Book("Kafka on the shore", "Haruki Murakami"));
        listViewItems.add(new Book("Pride and Prejudice", "Jane Austen"));
        listViewItems.add(new Book("Mảnh trăng cuối rừng", "Nguyễn Minh Châu"));
        listViewItems.add(new Book("One Hundred Years of Solitude", "Gabriel Garcia Marquez"));
        listViewItems.add(new Book("The Book Thief", "Markus Zusak"));
        listViewItems.add(new Book("The Hunger Games", "Suzanne Collins"));
        listViewItems.add(new Book("Số đỏ", "Vũ Trọng Phụng"));
        listViewItems.add(new Book("The Hitchhiker's Guide to the Galaxy", "Douglas Adams"));
        listViewItems.add(new Book("The Theory Of Everything", "Dr Stephen Hawking"));
        listViewItems.add(new Book("Đàn ghi-ta của Lorca", "Thanh Thảo"));
        listViewItems.add(new Book("The Trial", "Franz Kafka"));

        return listViewItems;
    }
}
    And the activity layout:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_horizontal_margin">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />

</RelativeLayout>
    POJO of the project:
Book.java
package info.devexchanges.staggeredrecyclerview;

public class Book {

    private String author;
    private String name;

    public Book(String bookName, String author) {
        this.name = bookName;
        this.author = author;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getName() {
        return name;
    }
}

Running application

    We'll have this output:
    When user click at any grid item:

Final thoughts

    This is the way to create a staggered grid view by RecyclerView. By searching on Internet, you can find out another solutions like customizing GridView widget or using external libraries. But, you should remember to RecyclerView as the "official widget" to dealing with this problem. Moreover, you should visit this tag link to read all post about it, source code of this project you can download from @Github.
    Reference: StaggeredGridLayoutManager in Google developer document.

Share


Previous post
« Prev Post
Next post
Next Post »