Android RecyclerView is more advanced version of ListView with improved performance and other benefits. Using RecyclerView and CardView together, both lists and grids can be created very easily. Here is the complete information about RecyclerView and other examples.
In this tutorial we are going to learn how to render a simple RecyclerView with a custom layout. We’ll also learn writing a adapter class, adding list divider and row click listener. The recycler view we are going to design contains list of movies displaying the title, genre and year of release.
Below is the RecyclerView widget with necessary attributes.
<android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"/>
Before you start, make sure that you updated your Android Studio to latest version. Currently my Android Studio is updated to Android Studio 2.0 Preview 6.
1. Creating New Project
1. In Android Studio, go to File ⇒ New Project and fill all the details required to create a new project. When it prompts to select a default activity, select Blank Activity and proceed.
2. Open build.gradle and add recycler view dependency. com.android.support:recyclerview-v7:23.1.1 and rebuild the project.
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:design:23.1.1' compile 'com.android.support:recyclerview-v7:23.1.1' }
3. With the latest version of build tools, Android Studio is creating two layout files for each activity. For main activity, it created activity_main.xml (contains CoordinatorLayout and AppBarLayout) and content_main.xml (for the actual content). Open content_main.xml and the recycler view widget.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/activity_main" tools:context=".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>
4. Open colors.xml located under res ⇒ values and add below colors.
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <color name="year">#999999</color> <color name="title">#222222</color> </resources>
2. Writing the Adapter Class
After adding the RecyclerView widget, let’s start writing the adapter class to render the data. The RecyclerView adapter is same as ListView but the override methods are different.
5. Create a class named Movie.java and declare title, genre and year. Also add the getter/setter methods to each variable.
package info.androidhive.recyclerview; public class Movie { private String title, genre, year; public Movie() { } public Movie(String title, String genre, String year) { this.title = title; this.genre = genre; this.year = year; } public String getTitle() { return title; } public void setTitle(String name) { this.title = name; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } public String getGenre() { return genre; } public void setGenre(String genre) { this.genre = genre; } }
6. Create an layout xml named movie_list_row.xml with the below code. This layout file renders a single row in recycler view by displaying movie name, genre and year of release.
<?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:focusable="true" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="10dp" android:paddingBottom="10dp" android:clickable="true" android:background="?android:attr/selectableItemBackground" android:orientation="vertical"> <TextView android:id="@+id/title" android:textColor="@color/title" android:textSize="16dp" android:text android:layout_alignParentTop="true" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/genre" android:layout_below="@id/title" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/year" android:textColor="@color/year" android:layout_width="wrap_content" android:layout_alignParentRight="true" android:layout_height="wrap_content" /> </RelativeLayout>
7. Now create a class named MoviesAdapter.java and add the below code. Here onCreateViewHolder() method inflates movie_list_row.xml. In onBindViewHolder() method the appropriate movie data (title, genre and year) set to each row.
package info.androidhive.recyclerview; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.List; public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MyViewHolder> { private List<Movie> moviesList; public class MyViewHolder extends RecyclerView.ViewHolder { public TextView title, year, genre; public MyViewHolder(View view) { super(view); title = (TextView) view.findViewById(R.id.title); genre = (TextView) view.findViewById(R.id.genre); year = (TextView) view.findViewById(R.id.year); } } public MoviesAdapter(List<Movie> moviesList) { this.moviesList = moviesList; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.movie_list_row, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { Movie movie = moviesList.get(position); holder.title.setText(movie.getTitle()); holder.genre.setText(movie.getGenre()); holder.year.setText(movie.getYear()); } @Override public int getItemCount() { return moviesList.size(); } }
8. Now open MainActivity.java and do the below changes. Here prepareMovieData() method adds sample data to list view.
package info.androidhive.recyclerview; import android.content.Context; import android.os.Bundle; 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.support.v7.widget.Toolbar; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private List<Movie> movieList = new ArrayList<>(); private RecyclerView recyclerView; private MoviesAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); recyclerView = (RecyclerView) findViewById(R.id.recycler_view); mAdapter = new MoviesAdapter(movieList); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(mAdapter); prepareMovieData(); } private void prepareMovieData() { Movie movie = new Movie("Mad Max: Fury Road", "Action & Adventure", "2015"); movieList.add(movie); movie = new Movie("Inside Out", "Animation, Kids & Family", "2015"); movieList.add(movie); movie = new Movie("Star Wars: Episode VII - The Force Awakens", "Action", "2015"); movieList.add(movie); movie = new Movie("Shaun the Sheep", "Animation", "2015"); movieList.add(movie); movie = new Movie("The Martian", "Science Fiction & Fantasy", "2015"); movieList.add(movie); movie = new Movie("Mission: Impossible Rogue Nation", "Action", "2015"); movieList.add(movie); movie = new Movie("Up", "Animation", "2009"); movieList.add(movie); movie = new Movie("Star Trek", "Science Fiction", "2009"); movieList.add(movie); movie = new Movie("The LEGO Movie", "Animation", "2014"); movieList.add(movie); movie = new Movie("Iron Man", "Action & Adventure", "2008"); movieList.add(movie); movie = new Movie("Aliens", "Science Fiction", "1986"); movieList.add(movie); movie = new Movie("Chicken Run", "Animation", "2000"); movieList.add(movie); movie = new Movie("Back to the Future", "Science Fiction", "1985"); movieList.add(movie); movie = new Movie("Raiders of the Lost Ark", "Action & Adventure", "1981"); movieList.add(movie); movie = new Movie("Goldfinger", "Action & Adventure", "1965"); movieList.add(movie); movie = new Movie("Guardians of the Galaxy", "Science Fiction & Fantasy", "2014"); movieList.add(movie); mAdapter.notifyDataSetChanged(); } }
Now if you run the app, you can see the movies displayed in a list manner.
4. Adding RecyclerView Item Click Listener
RecyclerView doesn’t have OnItemClickListener method too to identify item click. You need to write your own class extending RecyclerView.OnItemTouchListener.
11. Open MainActivity.java and add the below RecyclerTouchListener class along with ClickListener interface.
MainActivity.java public interface ClickListener { void onClick(View view, int position); void onLongClick(View view, int position); } public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener { private GestureDetector gestureDetector; private MainActivity.ClickListener clickListener; public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final MainActivity.ClickListener clickListener) { this.clickListener = clickListener; gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child != null && clickListener != null) { clickListener.onLongClick(child, recyclerView.getChildPosition(child)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { View child = rv.findChildViewUnder(e.getX(), e.getY()); if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) { clickListener.onClick(child, rv.getChildPosition(child)); } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } }
Finally add the recycler view item click listener as mentioned below.
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new ClickListener() { @Override public void onClick(View view, int position) { Movie movie = movieList.get(position); Toast.makeText(getApplicationContext(), movie.getTitle() + " is selected!", Toast.LENGTH_SHORT).show(); } @Override public void onLongClick(View view, int position) { } }));
Run the app and verify the item click. You should able to see a toast message upon clicking on a row. You can also notice that a background ripple effect when testing on lollipop device.
Final Code
Below is the complete code of my MainActivity.java
MainActivity.java package info.androidhive.recyclerview; import android.content.Context; import android.os.Bundle; 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.support.v7.widget.Toolbar; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private List<Movie> movieList = new ArrayList<>(); private RecyclerView recyclerView; private MoviesAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); recyclerView = (RecyclerView) findViewById(R.id.recycler_view); mAdapter = new MoviesAdapter(movieList); recyclerView.setHasFixedSize(true); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL)); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(mAdapter); recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new ClickListener() { @Override public void onClick(View view, int position) { Movie movie = movieList.get(position); Toast.makeText(getApplicationContext(), movie.getTitle() + " is selected!", Toast.LENGTH_SHORT).show(); } @Override public void onLongClick(View view, int position) { } })); prepareMovieData(); } private void prepareMovieData() { Movie movie = new Movie("Mad Max: Fury Road", "Action & Adventure", "2015"); movieList.add(movie); movie = new Movie("Inside Out", "Animation, Kids & Family", "2015"); movieList.add(movie); movie = new Movie("Star Wars: Episode VII - The Force Awakens", "Action", "2015"); movieList.add(movie); movie = new Movie("Shaun the Sheep", "Animation", "2015"); movieList.add(movie); movie = new Movie("The Martian", "Science Fiction & Fantasy", "2015"); movieList.add(movie); movie = new Movie("Mission: Impossible Rogue Nation", "Action", "2015"); movieList.add(movie); movie = new Movie("Up", "Animation", "2009"); movieList.add(movie); movie = new Movie("Star Trek", "Science Fiction", "2009"); movieList.add(movie); movie = new Movie("The LEGO Movie", "Animation", "2014"); movieList.add(movie); movie = new Movie("Iron Man", "Action & Adventure", "2008"); movieList.add(movie); movie = new Movie("Aliens", "Science Fiction", "1986"); movieList.add(movie); movie = new Movie("Chicken Run", "Animation", "2000"); movieList.add(movie); movie = new Movie("Back to the Future", "Science Fiction", "1985"); movieList.add(movie); movie = new Movie("Raiders of the Lost Ark", "Action & Adventure", "1981"); movieList.add(movie); movie = new Movie("Goldfinger", "Action & Adventure", "1965"); movieList.add(movie); movie = new Movie("Guardians of the Galaxy", "Science Fiction & Fantasy", "2014"); movieList.add(movie); mAdapter.notifyDataSetChanged(); } public interface ClickListener { void onClick(View view, int position); void onLongClick(View view, int position); } public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener { private GestureDetector gestureDetector; private MainActivity.ClickListener clickListener; public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final MainActivity.ClickListener clickListener) { this.clickListener = clickListener; gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { View child = recyclerView.findChildViewUnder(e.getX(), e.getY()); if (child != null && clickListener != null) { clickListener.onLongClick(child, recyclerView.getChildPosition(child)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { View child = rv.findChildViewUnder(e.getX(), e.getY()); if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) { clickListener.onClick(child, rv.getChildPosition(child)); } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } } }
Be the first one to write a response :(
{{ reply.member.name }} - {{ reply.created_at_human_readable }}