How to use Android RecyclerView in your Android app. Learn how to create custom RecyclerView Adapter and how to customize its look and feel
Android RecyclerView is an important component widely used in Android apps. It is important to know how to use it and how to customize its behavior. This tutorial will cover some important aspects of Android RecyclerView giving all the information you need to build a great Android app using it.
As you may already know, Android RecyclerView is a new component introduced in Android Lollipop. This component increases performances respect to Android ListView. Moreover, respect to Android ListView, Android RecyclerView is much more customizable using Android Recyclerview adapter.
In this tutorial, we will learn how to:
- how to use Android RecyclerView with a custom layout
- intercept user touch events
- customize RecyclerView appearance
The Android source code is downloadable here:
Getting started with Android RecyclerView Adapter
Android RecyclerView uses an Adapter to represent the information we want to show as a list. Even in Android ListView we use an adapter. Anyway, Android RecyclerView extends this concept and improves the way this adapter is used to increase overall performances.
The adapter is a class that extends RecyclerView.Adapter and stands behind the UI and the underlying data we want to represent. For this reason, we have to customize it to use our class that represents the information.
To start using Android RecyclerView we have to import the support library in the gradle file:
[xml]dependencies {….
compile ‘com.android.support:recyclerview-v7:<latest-version>’
}[/xml]
Now, we are ready to use the RecyclerView UI component. To make things simple, we will use, as the data layer, a simple class that represents the country and the respective population:
[java]public class Country {protected String name;
protected double population;
public Country(String name, double population) {
this.name = name;
this.population = population;
}
}[/java]
The next step is defining it in the android layout file:
[xml] <RelativeLayoutxmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:paddingBottom=”@dimen/activity_vertical_margin”
android:paddingLeft=”@dimen/activity_horizontal_margin”
android:paddingRight=”@dimen/activity_horizontal_margin”
android:paddingTop=”@dimen/activity_vertical_margin”
app:layout_behavior=”@string/appbar_scrolling_view_behavior”
tools:context=”com.survivingwithandroid.recyclerview.MainActivity”
tools:showIn=”@layout/activity_main”>
<android.support.v7.widget.RecyclerView
android:id=”@+id/recycler_view”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:scrollbars=”vertical”/>
</RelativeLayout>[/xml]
and get the reference in our class so that we can use it:
[java]RecyclerView rv = (RecyclerView) findViewById(R.id.recycler_view);[/java]At this moment, the Android RecyclerView is empty, we have to implement our adapter.
[java]public class CountryAdapter extends
RecyclerView.Adapter<CountryAdapter.MyViewHolder> {
private List<Country> countryList;
/**
* View holder class
* */
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView countryText;
public TextView popText;
public MyViewHolder(View view) {
super(view);
countryText = (TextView) view.findViewById(R.id.countryName);
popText = (TextView) view.findViewById(R.id.pop);
}
}
public CountryAdapter(List<Country> countryList) {
this.countryList = countryList;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Country c = countryList.get(position);
holder.countryText.setText(c.name);
holder.popText.setText(String.valueOf(c.population));
}
@Override
public int getItemCount() {
return countryList.size();
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row,parent, false);
return new MyViewHolder(v);
}
}[/java]
There are some important methods we have to override to customize the Android RecyclerView behavior. First of all, notice at the beginning, we have created a simple class (MyViewHolder
) that holds the references to the row UI components. This class implements the View-Holder pattern.
Next, in onCreateViewHolder
we inflate the row layout returning an instance of the class MyViewHolder
. In this simple example, the row layout is:
android:orientation=”vertical” android:layout_width=”wrap_content”
android:layout_height=”wrap_content”>
<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:id=”@+id/countryName”
android:textStyle=”bold”
/>
<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:id=”@+id/pop”/>
</LinearLayout>[/xml]
Finally, we override onBindViewHolder
that binds our data to the UI. This method, simply, retrieves the data from an ArrayList. According to the current index position, it stores the values into the MyViewHolder.
Now it is time to set the adapter into the Android RecyclerView:
rv.setAdapter(ca);
[/java]
Don’t forget to set the layout manager:
[java] LinearLayoutManager llm = new LinearLayoutManager(this);llm.setOrientation(LinearLayoutManager.VERTICAL);
rv.setLayoutManager(llm);[/java]
Running the example, we have:
Android RecyclerView Item click: Intercept user touch events
Now that our component is configured and shows the information as a list, it is time to handle user clicks on RecyclerView items. In other words, we want to know if a user clicks on an item and what type of click he is making: simple click or long click.
When we use Android RecyclerView the things are a little more complex than Android ListView. In this case, we have to create a class that implements RecyclerView.OnItemTouchListener.
implements RecyclerView.OnItemTouchListener {
private RecyclerTouchListener listener;
private GestureDetector gd;
public interface RecyclerTouchListener {
public void onClickItem(View v, int position) ;
public void onLongClickItem(View v, int position);
}
public RecyclerItemListener(Context ctx, final RecyclerView rv,
final RecyclerTouchListener listener) {
this.listener = listener;
gd = new GestureDetector(ctx,
new GestureDetector.SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent e) {
// We find the view
View v = rv.findChildViewUnder(e.getX(), e.getY());
// Notify the even
listener.onLongClickItem(v, rv.getChildAdapterPosition(v));
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
View v = rv.findChildViewUnder(e.getX(), e.getY());
// Notify the even
listener.onClickItem(v, rv.getChildAdapterPosition(v));
return true;
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
return ( child != null && gd.onTouchEvent(e));
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}[/java]
We define a callback interface to notify the listener when the user clicks on an item. The first thing is creating an instance of GestureDetector. In this way we can know when a user clicks and what click type he is doing.
It is important to note that our class overrides onInterceptTouchEvent
to know if the user selects and item and if the gesture detected is handled by our instance.
To receive notification in the listener class, we implement the interface declared above:
new RecyclerItemListener.RecyclerTouchListener() {
public void onClickItem(View v, int position) {
System.out.println(“On Click Item interface”);
}
public void onLongClickItem(View v, int position) {
System.out.println(“On Long Click Item interface”);
}
}));[/java]
How to customize Android RecyclerView
The next step is customizing the Android RecyclerView using divider color for example. There are several aspects that can be customized. To do it we have to implement a custom class that extends RecyclerView.ItemDecoration. As a first example, we will change the spacing between the Recyclerview row:
[java] public class VerticalSpacingDecoration extends RecyclerView.ItemDecoration {private int spacing;
public VerticalSpacingDecoration(int spacing) {
this.spacing = spacing;
}
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent,
RecyclerView.State state) {
outRect.bottom = spacing;
}
}[/java]
In this example, we have overriden getItemOffsets
implementing how spacing looks like. Moreover, we have to tell to the RecyclerView that we want to use a custom decoration:
Running the example we have:
In conclusion, we will add another Recyclerview customization: row divider. In this case, Android RecyclerView is different from Android ListView because we have to implement a custom decorator. This is very simple:
private Drawable mDivider;
public DividerItemDecoration(Drawable divider) {
this.mDivider = divider;
}
@Override
public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() – parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
child.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
}
}[/java]
In this class, we override onDrawOver
and implements our UI customizazion.
To set this decorator:
new DividerItemDecoration(ContextCompat.getDrawable(getApplicationContext(),
R.drawable.item_decorator)));[/java]
where item_decorator
is defined under drawable directory in this way:
android:shape=”rectangle”>
<size android:height=”1dp” />
<solid android:color=”#ff992900″ />
</shape>[/xml]
Running the example we have:
At the end of this post, hopefully, you gained the knowledge about Android RecyclerView and how to customize it according to your needs.