Table of Contents
What is RecyclerView?
RecyclerView is an advanced version of ListView with improved performance and customizability. It was included in API level 22 (Lollipop) in the support-v7 library. RecyclerView is used in most of the apps. It can be used when we want to display a list of items through which the user can scroll. Each item in the list rendered by a layout file.
In this tutorial, we will learn how to:
- create a RecyclerView with a custom adapter.
- add a divider using ItemDecoration.
- add touch events like onClickItem and onLongPress.
Creating Project and Adding Dependencies
1. Create a new Project in Android Studio with the name “Recycler View Demo” and package name com.androiddeft.recyclerviewdemo.
2. Now open build.gradle file and add RecyclerView dependency as shown below:
1 2 3 4 5 6 7 8 9 |
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.0.1' testCompile 'junit:junit:4.12' compile 'com.android.support:recyclerview-v7:25.0.1' } |
3. Open activity_main.xml and add RecyclerView widget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.androiddeft.recyclerviewdemo.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="vertical" /> </RelativeLayout> |
Creating the Custom Adapter
In this tutorial, we will be listing Top 10 Hollywood movies along with their genre, year of release and rating.
1. First of all, let’s create a new package named beans (com.androiddeft.recyclerviewdemo.beans) inside the main package.
2. Now create a new POJO named Movie inside the beans package with the following code. This class will help in holding the movie details:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package com.androiddeft.recyclerviewdemo.beans; /** * Created by Abhi on 23 Sep 2017 023. */ public class Movie { private String movieName; private String genre; private Integer year; private Double rating; public Movie(String movieName, String genre, Integer year, Double rating) { this.movieName = movieName; this.genre = genre; this.year = year; this.rating = rating; } public String getMovieName() { return movieName; } public String getGenre() { return genre; } public Integer getYear() { return year; } public Double getRating() { return rating; } } |
3. Create a new layout filed named movie_list.xml. This will represent an individual item. This layout has TextViews to display movie name, genre, year of release and rating. It also has an ImageView to display the star.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="true" android:clickable="true" android:background="?android:attr/selectableItemBackground" > <TextView android:id="@+id/movieName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_marginLeft="17dp" android:layout_marginStart="17dp" android:layout_marginTop="13dp" android:text="Movie Name" android:textSize="18dp" android:textColor="@color/colorPrimaryDark" /> <TextView android:id="@+id/genre" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/movieName" android:layout_alignStart="@+id/movieName" android:layout_below="@+id/movieName" android:text="Crime, Drama" /> <ImageView android:id="@+id/ratingImg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/movieName" android:layout_toLeftOf="@+id/rating" android:layout_toStartOf="@+id/rating" app:srcCompat="@android:drawable/btn_star_big_on" /> <TextView android:id="@+id/year" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignEnd="@+id/rating" android:layout_alignRight="@+id/rating" android:layout_below="@+id/ratingImg" android:text="2016" android:textColor="@color/colorAccent" /> <TextView android:id="@+id/rating" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="25dp" android:layout_marginRight="25dp" android:text="9.2" android:layout_centerVertical="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> </RelativeLayout> |
The android:clickable and android:background attributes help in creating the ripple effect whenever an item is clicked.
4. Now create a class named MoviesAdapter.java. This class will act as an adapter for the RecyclerView. It has a simple class named CustomViewHolder, which extends the ViewHolder class of RecyclerView and defines the initializes the views. MoviesAdapter class overrides the onCreateViewHolder method, which inflates movie_list layout. It also overrides onBindViewHolder, which helps in setting movie attributes to the view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package com.androiddeft.recyclerviewdemo; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.androiddeft.recyclerviewdemo.beans.Movie; import java.util.List; /** * Created by Abhi on 23 Sep 2017 023. */ public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.CustomViewHolder> { private List<Movie> movies; public class CustomViewHolder extends RecyclerView.ViewHolder { public TextView movieName, year, genre, rating; public CustomViewHolder(View view) { super(view); movieName = (TextView) view.findViewById(R.id.movieName); genre = (TextView) view.findViewById(R.id.genre); year = (TextView) view.findViewById(R.id.year); rating = (TextView) view.findViewById(R.id.rating); } } public MoviesAdapter(List<Movie> movies) { this.movies = movies; } @Override public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.movie_list, parent, false); return new CustomViewHolder(itemView); } @Override public void onBindViewHolder(CustomViewHolder holder, int position) { Movie movie = movies.get(position); holder.movieName.setText(movie.getMovieName()); holder.genre.setText(movie.getGenre()); holder.year.setText(String.valueOf(movie.getYear())); holder.rating.setText(String.valueOf(movie.getRating())); } @Override public int getItemCount() { return movies.size(); } } |
5. Now open MainActivity.java and add a method named populateMovieDetails, which populates the Movie Details. Define the RecyclerView and set the instance of MoviesAdapter as the adapter. Also, set the LayoutManager and ItemAnimator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
package com.androiddeft.recyclerviewdemo; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Toast; import com.androiddeft.recyclerviewdemo.beans.Movie; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { List<Movie> movies = new ArrayList<>(); private RecyclerView recyclerView; private MoviesAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.recycler_view); mAdapter = new MoviesAdapter(movies); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(mAdapter); populateMovieDetails(); mAdapter.notifyDataSetChanged(); } private void populateMovieDetails() { movies.add(new Movie("The Shawshank Redemption", "Crime, Drama", 1994, 9.2)); movies.add(new Movie("The Godfather", "Crime, Drama", 1972, 9.2)); movies.add(new Movie("The Godfather: Part II", "Crime, Drama", 1974, 9.0)); movies.add(new Movie("The Dark Knight", "Action, Crime, Drama", 2008, 9.0)); movies.add(new Movie("12 Angry Men", "Crime, Drama", 1974, 8.9)); movies.add(new Movie("Schindler's List", "Biography, Drama, History", 1993, 8.9)); movies.add(new Movie("Pulp Fiction", "Crime, Drama", 1994, 8.9)); movies.add(new Movie("The Lord of the Rings", "Adventure, Drama, Fantasy", 2003, 8.9)); movies.add(new Movie("The Good, the Bad and the Ugly", "Western", 1967, 8.9)); movies.add(new Movie("Fight Club", "Drama", 1999, 8.8)); } } |
Now run the application and you will see list of Top 10 Hollywood Movies as shown below:
Adding Divider or Separator
In order to add a divider,
1. Define the separator in the drawable folder named item_seperator.xml
1 2 3 4 5 |
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <size android:height="1dp" /> <solid android:color="#aaa" /> </shape> |
2. Now create a class named DividerItemDecoration, which extends the RecyclerView.ItemDecoration class. We override the onDrawOver class in order to draw the separator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.androiddeft.recyclerviewdemo; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v7.widget.RecyclerView; import android.view.View; /** * Created by Abhi on 25 Sep 2017 025. */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { 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); } } } |
3. In the MainActivity class, add the Item Decoration to the RecyclerView.
1 2 3 |
recyclerView.addItemDecoration( new DividerItemDecoration(ContextCompat.getDrawable(getApplicationContext(), R.drawable.item_seperator))); |
When you run the application now you should see separators added as shown below:

Adding Touch Events
To add the Touch events, you need to implement the RecyclerView.OnItemTouchListener interface. Create a class named RecyclerItemListener and add an interface named RecyclerTouchListener with 2 method signatures for onClick and onLongClick.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
package com.androiddeft.recyclerviewdemo; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; /** * Created by Abhi on 25 Sep 2017 025. */ public class RecyclerItemListener 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 Long click event listener.onLongClickItem(v, rv.getChildAdapterPosition(v)); } @Override public boolean onSingleTapUp(MotionEvent e) { View v = rv.findChildViewUnder(e.getX(), e.getY()); // Notify the click event 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) { } } |
In MainActivity, add OnItemTouchListener for the RecyclerView, which takes the instance of RecyclerItemListener as the parameter. RecyclerItemListener instance defines onClickItem and onLongClickItem. We have added Toast messages to display which item has been clicked.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
recyclerView.addOnItemTouchListener(new RecyclerItemListener(getApplicationContext(), recyclerView, new RecyclerItemListener.RecyclerTouchListener() { @Override public void onClickItem(View v, int position) { Toast.makeText(getApplicationContext(), "Clicked: " + movies.get(position).getMovieName(), Toast.LENGTH_SHORT).show(); } @Override public void onLongClickItem(View v, int position) { Toast.makeText(getApplicationContext(), "Long Pressed: " + movies.get(position).getMovieName(), Toast.LENGTH_SHORT).show(); } })); |
The Complete MainActivity class
Here goes the complete MainActivity which has RecyclerView with adapter, divider and touch events.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
package com.androiddeft.recyclerviewdemo; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.Toast; import com.androiddeft.recyclerviewdemo.beans.Movie; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { List<Movie> movies = new ArrayList<>(); private RecyclerView recyclerView; private MoviesAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.recycler_view); mAdapter = new MoviesAdapter(movies); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(mAdapter); populateMovieDetails(); mAdapter.notifyDataSetChanged(); recyclerView.addOnItemTouchListener(new RecyclerItemListener(getApplicationContext(), recyclerView, new RecyclerItemListener.RecyclerTouchListener() { @Override public void onClickItem(View v, int position) { Toast.makeText(getApplicationContext(), "Clicked: " + movies.get(position).getMovieName(), Toast.LENGTH_SHORT).show(); } @Override public void onLongClickItem(View v, int position) { Toast.makeText(getApplicationContext(), "Long Pressed: " + movies.get(position).getMovieName(), Toast.LENGTH_SHORT).show(); } })); recyclerView.addItemDecoration( new DividerItemDecoration(ContextCompat.getDrawable(getApplicationContext(), R.drawable.item_seperator))); } private void populateMovieDetails() { movies.add(new Movie("The Shawshank Redemption", "Crime, Drama", 1994, 9.2)); movies.add(new Movie("The Godfather", "Crime, Drama", 1972, 9.2)); movies.add(new Movie("The Godfather: Part II", "Crime, Drama", 1974, 9.0)); movies.add(new Movie("The Dark Knight", "Action, Crime, Drama", 2008, 9.0)); movies.add(new Movie("12 Angry Men", "Crime, Drama", 1974, 8.9)); movies.add(new Movie("Schindler's List", "Biography, Drama, History", 1993, 8.9)); movies.add(new Movie("Pulp Fiction", "Crime, Drama", 1994, 8.9)); movies.add(new Movie("The Lord of the Rings", "Adventure, Drama, Fantasy", 2003, 8.9)); movies.add(new Movie("The Good, the Bad and the Ugly", "Western", 1967, 8.9)); movies.add(new Movie("Fight Club", "Drama", 1999, 8.8)); } } |
You can see in the following animation the ripple effect, toast messages when clicked and long pressed. If you face any error while coding or following this tutorial, do post them in the comments section. Happy coding!
Download Source CodeDownload APK
Abhishek
Latest posts by Abhishek (see all)
- Accessing Camera and Taking Pictures in Android - April 27, 2019
- Android: Download File from URL with Progress Bar - March 18, 2018
- Android: Uploading File to Server with Progress Bar - February 18, 2018