Android GridLayoutManager is the RecyclerView.LayoutManager
implementation to lay out items in a grid. In this tutorial, we’ll create an application that displays CardViews inside a RecyclerView in the form of a GridLayout. Also, we’ll implement an interface that makes RecyclerView item click similar to a ListView itemClickListener
.
We’ve implemented a RecyclerView using a LinearLayoutManager here. Now let’s use a GridLayoutManager
to layout the RecyclerView as a grid. Following is the constructor for a GridLayoutManager.
GridLayoutManager (Context context,
int spanCount,
int orientation,
boolean reverseLayout)
reverseLayout if set true then layout items from end to start. To set the span size for each item, we invoke the method setSpanSizeLookup
on the GridLayoutManager Let’s implement RecyclerView using a GridLayoutManager in a new Android Studio project.
The project consists of a single Activity : MainActivity.java
, an adapter class : RecyclerViewAdapter.java
, a DataModel.java
class and a custom GridLayoutManager class AutoFitGridLayoutManager.java
. The xml layout of the MainActivity.java class is defined in the file activity_main.xml
as
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
Note: Don’t forget to add the following dependencies for Material Design widgets and CardView
in the build.gradle file.
compile 'com.android.support:cardview-v7:25.1.1'
compile 'com.android.support:design:25.1.1'
The DataModel.java
class is given below: package com.journaldev.recyclerviewgridlayoutmanager;
public class DataModel {
public String text;
public int drawable;
public String color;
public DataModel(String t, int d, String c )
{
text=t;
drawable=d;
color=c;
}
}
The DataModel class will hold the text, drawable icon and background colour of each item cell. The RecyclerViewAdapter.java class is given below:
package com.journaldev.recyclerviewgridlayoutmanager;
import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class RecyclerViewAdapter extends RecyclerView.Adapter {
ArrayList mValues;
Context mContext;
protected ItemListener mListener;
public RecyclerViewAdapter(Context context, ArrayList values, ItemListener itemListener) {
mValues = values;
mContext = context;
mListener=itemListener;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView textView;
public ImageView imageView;
public RelativeLayout relativeLayout;
DataModel item;
public ViewHolder(View v) {
super(v);
v.setOnClickListener(this);
textView = (TextView) v.findViewById(R.id.textView);
imageView = (ImageView) v.findViewById(R.id.imageView);
relativeLayout = (RelativeLayout) v.findViewById(R.id.relativeLayout);
}
public void setData(DataModel item) {
this.item = item;
textView.setText(item.text);
imageView.setImageResource(item.drawable);
relativeLayout.setBackgroundColor(Color.parseColor(item.color));
}
@Override
public void onClick(View view) {
if (mListener != null) {
mListener.onItemClick(item);
}
}
}
@Override
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder Vholder, int position) {
Vholder.setData(mValues.get(position));
}
@Override
public int getItemCount() {
return mValues.size();
}
public interface ItemListener {
void onItemClick(DataModel item);
}
}
In the above code we’ve defined an ItemListener interface that’ll be implemented in the MainActivity.java class. The xml layout for each RecyclerView item is given below. recycler_view_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:card_view="https://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="150dp"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="@dimen/margin10"
card_view:cardMaxElevation="@dimen/margin10"
card_view:contentPadding="@dimen/margin10">
<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="center">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:tint="@android:color/white"
android:padding="5dp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textColor="@android:color/white"
android:layout_below="@+id/imageView" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
The AutoFitGridLayoutManager.java class is given below:
package com.journaldev.recyclerviewgridlayoutmanager;
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
public class AutoFitGridLayoutManager extends GridLayoutManager {
private int columnWidth;
private boolean columnWidthChanged = true;
public AutoFitGridLayoutManager(Context context, int columnWidth) {
super(context, 1);
setColumnWidth(columnWidth);
}
public void setColumnWidth(int newColumnWidth) {
if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
columnWidth = newColumnWidth;
columnWidthChanged = true;
}
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (columnWidthChanged && columnWidth > 0) {
int totalSpace;
if (getOrientation() == VERTICAL) {
totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
} else {
totalSpace = getHeight() - getPaddingTop() - getPaddingBottom();
}
int spanCount = Math.max(1, totalSpace / columnWidth);
setSpanCount(spanCount);
columnWidthChanged = false;
}
super.onLayoutChildren(recycler, state);
}
}
The span count is dynamically calculated based on the orientation, width and height available. The MainActivity.java class
is given below:
package com.journaldev.recyclerviewgridlayoutmanager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements RecyclerViewAdapter.ItemListener {
RecyclerView recyclerView;
ArrayList arrayList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
arrayList = new ArrayList();
arrayList.add(new DataModel("Item 1", R.drawable.battle, "#09A9FF"));
arrayList.add(new DataModel("Item 2", R.drawable.beer, "#3E51B1"));
arrayList.add(new DataModel("Item 3", R.drawable.ferrari, "#673BB7"));
arrayList.add(new DataModel("Item 4", R.drawable.jetpack_joyride, "#4BAA50"));
arrayList.add(new DataModel("Item 5", R.drawable.three_d, "#F94336"));
arrayList.add(new DataModel("Item 6", R.drawable.terraria, "#0A9B88"));
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, arrayList, this);
recyclerView.setAdapter(adapter);
/**
AutoFitGridLayoutManager that auto fits the cells by the column width defined.
**/
/*AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
recyclerView.setLayoutManager(layoutManager);*/
/**
Simple GridLayoutManager that spans two columns
**/
GridLayoutManager manager = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(manager);
}
@Override
public void onItemClick(DataModel item) {
Toast.makeText(getApplicationContext(), item.text + " is clicked", Toast.LENGTH_SHORT).show();
}
}
RecyclerViewAdapter.ItemListener
and overrides the method onItemClick
that’s defined in the adapter class. By doing this, we’ve implemented the RecyclerView Click Listener within our Activity instead of the Adapter class(similar to the standard onItemClickListener defined for a ListView)Let’s see the output of the application with the standard GridLayoutManager code. As you can see, each row has two items that span the column width in both orientations. Now comment out the code for simple GridLayoutManager and run the code for AutoFitGridLayoutManager
AutoFitGridLayoutManager layoutManager = new AutoFitGridLayoutManager(this, 500);
recyclerView.setLayoutManager(layoutManager);
The output of the application in action is given below. As you can see in the above output, when the orientation changes to landscape, each row has three items, thereby dynamically sizing the items to auto-fit the column width. This brings an end to this tutorial. You can download the final android GridLayoutManager project from the link given below.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
Thank you very much for your example!
- Peter
Please what can you do to ensure that each item clicked opens a new activity? Thanks
- Teddy Ben
HI, My Adapter gives the error that i should implement the onBindViewHolder method. Can you help? Please.
- Paulo Alexandre Neto Valentim
The autofit grid is working for me . thanks for the help
- wanfadger
Thanks for the article! Especially for the AutoFitGridLayoutManager class
- Kirill Karmazin
How To open New Activity on click grid item
- Vinod Prajapat
It show the error: cannot find symbol method setData(Object) , So plz help me
- Pooja Sehrawat
Thanks for your post, it’s very useful I want to have this Grid items with different heights, can you explain how we can do this. As per the above code all card view items have equal heights, can you make all this are with own context heights, like flexible card items.
- Naresh
thankxx for sharing code. this is very helpful for me.
- junaid khan
You should redo this tutorial - there are so many bad coding habits in it eg. your dataModel: don’t use t,d,c as parameters in a function signature!! use expressive names like what the really stand for like text, drawable and color - you can always use this.text = text in the body and keep your codestyle common over ALL files in this tutorial! the naming problem is quite huge in this tutorial: recycler_view_item.xml - the relativelayout is a button_wrapper, the drawable the button_icon the textview is the button text or something else… and be consistent about using hungarian notation - look at “say mNo” - by jake wharton If you do a tutorial like this - make it exceptionally good so that other people can learn Android in a good way. I don’t want to bash you - if you are doing something you gotta be doing it right!
- A Friend