Android RecyclerView with Material Design

Android RecyclerView with Material Design

In this tutorial we are going to learn how to implement android RecyclerView with Material Design. I wrote a post on android ToolBar with Material Design. Part of the post will be used in this current android RecyclerView tutorial.

Android L introduced Material Design which is basically a new design pattern which is backward compatible to android version less than 5 through android support library. With Material Design, future android version will maintain a uniform design pattern for its user interface. The android support library version 7 is updated so that it can be used for backward compatibility for less versions.

Android RecyclerView is a new ViewGroup introduce in android L. It is similar but more complicated than the ListView. it is also more efficient than the ListView. This widget is a container for displaying large data sets that can be scrolled very efficiently by maintaining a limited number of views. Use the RecyclerView widget when you have data collections whose elements change at runtime based on user action or network events.

Android RecyclerView requires a layout manager and an adapter for displaying and handling of its dataset.

We are going to create our project main layout which will contain the RecyclerView. In addition to this layout, will go further and create our adapter class and a ViewHolder class. The entity class will be used to wrap a single item row in the RecyclerView in an object.

Below is an image that represents what we are going to achieve at the end of this tutorial.

Android RecyclerView with Material Design

Lets start with the code and project setup so that it will make sense as we follow the tutorial along.

Before we start, the first thing I will do is to list the environment and tools I used in this android tutorial but feel free to use whatever environment or tools you are familiar with.

Windows 7

Android Studio

Sony Xperia ZL

Min SDK 14

Target SDK 19

To create a new android application project, following the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidRecyclerView

Package: com.inducesmile.androidrecyclerview

Keep other default selections.

Continue to click on next button until Finish button is active, then click on Finish Button

Once you are done with creating your project, make sure you change the package name if you did not use the same package.

In other to use RecyclerView in our layout file and the Circular ImageView library, we are going to update our build.gradle file.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.android.support:recyclerview-v7:21.0.+'
    compile 'de.hdodenhof:circleimageview:1.2.1'
}

Now that we have added all our project dependencies, we will move over to the main layout file (activity_main.xml) for our application. Since I am using the default layout created by my project, open the layout file and add the code to the file.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="64dp"
    android:background="@color/color_primary"
    android:minHeight="?attr/actionBarSize" />

<RelativeLayout
    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"
    tools:context=".MainActivity">

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

</RelativeLayout>

</LinearLayout>

Since we are using the android ToolBar, we are going to modify our project styles.xml file. To learn more about this, please refer to the link above which relates to android ToolBar with Material Design. The modified version of our styles.xml file is as shown

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/color_primary</item>
        <item name="colorPrimaryDark">@color/color_primary_dark</item>
        <item name="colorAccent">@color/accent_color</item>
    </style>
</resources>

We have add some string resources in the strings.xml file. The updated version of this file is as shown. Copy and paste the code in your project strings.xml file.

<resources>
<string name="app_name">Android RecyclerView</string>
<string name="action_settings">Settings</string>
<string name="action_refresh">Settings</string>
<string name="action_new">Settings</string>
<string name="logo_desc">App logo</string>
<string name="person_name">Kate Jennifer</string>
<string name="person_address">24 Lords Crescent, USA </string>
</resources>

In our new ToolBar ViewGroup, we add two action views in the project menu_main.xml file. Copy the code in this file and paste it in your project menu_main.xml file.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">

    <item
        android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        app:showAsAction="never" />

    <item android:id="@+id/action_refresh"
        android:title="@string/action_refresh"
        android:icon="@drawable/ic_action_refresh"
        android:orderInCategory="200"
        app:showAsAction="ifRoom" />

    <item android:id="@+id/action_new"
        android:title="@string/action_new"
        android:icon="@drawable/ic_action_new"
        android:orderInCategory="300"
        app:showAsAction="ifRoom" />
</menu>

Lets focus on the adapter class that the RecyclerView will use to bind each item of our dataset. As I mention previously, just like ListView, RecyclerView also requires an adapter. The adapter is slightly different but the RecyclerView adapter uses the View Holder pattern to bind corresponding View components to its data. The RecyclerView adapters extend RecyclerView.Adapter and will override three methods – onCreateViewHolder(ViewGroup parent, int viewType) , onBindViewHolder(RecyclerViewHolders holder, int position)  and getItemCount() .

The complete code for the RecyclerView adapter is as shown below.

package inducesmile.com.androidrecyclerview;

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

import java.util.List;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolders> {

    private List<ItemObject> itemList;
    private Context context;

    public RecyclerViewAdapter(Context context, List<ItemObject> itemList) {
        this.itemList = itemList;
        this.context = context;
    }

    @Override
    public RecyclerViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {

        View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, null);
        RecyclerViewHolders rcv = new RecyclerViewHolders(layoutView);
        return rcv;
    }

    @Override
    public void onBindViewHolder(RecyclerViewHolders holder, int position) {
        holder.personName.setText(itemList.get(position).getName());
        holder.personAddress.setText(itemList.get(position).getAddress());
        holder.personPhoto.setImageResource(itemList.get(position).getPhotoId());
    }

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

You can see that the adapter class inflates a layout. This layout is what will hold all View component of a single RecyclerView item. In our project we are going to use two TextView and one ImageView controls. The sources code for the item_list.xml layout is as shown.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_margin="8dp"
    android:paddingTop="8dp"
    android:paddingBottom="8dp"
    android:layout_height="wrap_content">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/circleView"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginTop="8dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:src="@drawable/face" />

    <TextView
        android:id="@+id/person_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/person_name"
        android:layout_alignTop="@+id/circleView"
        android:layout_toRightOf="@+id/circleView"
        android:layout_marginTop="1dp"
        android:layout_marginLeft="18dp"
        android:textSize="16sp"
        android:textStyle="bold"
        android:textColor="@color/accent_color"
        android:layout_toEndOf="@+id/circleView" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/person_address"
        android:id="@+id/person_address"
        android:textSize="12sp"
        android:layout_marginTop="2dp"
        android:layout_below="@+id/person_name"
        android:layout_alignLeft="@+id/person_name"
        android:layout_alignStart="@+id/person_name" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/color_primary"
        android:layout_below="@+id/circleView"
        android:layout_alignLeft="@+id/circleView"
        android:layout_marginTop="8dp"
    />

</RelativeLayout>

The RecyclerView Adapter uses the RecyclerViewHolder class which contains our View components for UI creation and data binding. Copy the code from this class and paste it on your project.

package inducesmile.com.androidrecyclerview;


import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class RecyclerViewHolders extends RecyclerView.ViewHolder{

    public TextView personName;
    public TextView personAddress;
    public ImageView personPhoto;

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

        personName = (TextView)itemView.findViewById(R.id.person_name);
        personAddress = (TextView)itemView.findViewById(R.id.person_address);
        personPhoto = (ImageView)itemView.findViewById(R.id.circleView);
    }
}

The entity object contain the corresponding values for the three View controls used for each RecyclerView item. The item object is stored in a List class which is passed as a parameter when the instance of the adapter class is created. The entity class code is as shown.

package inducesmile.com.androidrecyclerview;


public class ItemObject {

    private String name;
    private String address;
    private int photoId;

    public ItemObject(String name, String address, int photoId) {
        this.name = name;
        this.address = address;
        this.photoId = photoId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getPhotoId() {
        return photoId;
    }

    public void setPhotoId(int photoId) {
        this.photoId = photoId;
    }
}

Finally, we will create a method which will return all our store item object in a List object. We will use an instance of a LinearLayoutManager to set the RecyclerView layout manager. The object of the adapter class is pass to RecyclerView method setAdapter(); The code in our MainActivity.java file is very simple and straight forward.

package inducesmile.com.androidrecyclerview;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

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


public class MainActivity extends ActionBarActivity {

    private LinearLayoutManager lLayout;

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

        Toolbar topToolBar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(topToolBar);
        topToolBar.setLogo(R.drawable.logo);
        topToolBar.setLogoDescription(getResources().getString(R.string.logo_desc));

        List<ItemObject> rowListItem = getAllItemList();
        lLayout = new LinearLayoutManager(MainActivity.this);

        RecyclerView rView = (RecyclerView)findViewById(R.id.recycler_view);
        rView.setLayoutManager(lLayout);

        RecyclerViewAdapter rcAdapter = new RecyclerViewAdapter(MainActivity.this, rowListItem);
        rView.setAdapter(rcAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
        if(id == R.id.action_refresh){
            Toast.makeText(MainActivity.this, "Refresh App", Toast.LENGTH_LONG).show();
        }
        if(id == R.id.action_new){
            Toast.makeText(MainActivity.this, "Create Text", Toast.LENGTH_LONG).show();
        }
        return super.onOptionsItemSelected(item);
    }

    private List<ItemObject> getAllItemList(){

        List<ItemObject> allItems = new ArrayList<ItemObject>();
        allItems.add(new ItemObject("Peter James", "Vildansvagen 19, Lund Sweden", R.drawable.face));
        allItems.add(new ItemObject("Henry Jacobs", "3 Villa Crescent London, UK", R.drawable.face));
        allItems.add(new ItemObject("Bola Olumide", "Victoria Island Lagos, Nigeria", R.drawable.face));
        allItems.add(new ItemObject("Chidi Johnson", "New Heaven Enugu, Nigeria", R.drawable.face));
        allItems.add(new ItemObject("DeGordio Puritio", "Italion Gata, Padova, Italy", R.drawable.face));
        allItems.add(new ItemObject("Gary Cook", "San Fransisco, United States", R.drawable.face));
        allItems.add(new ItemObject("Edith Helen", "Queens Crescent, New Zealand", R.drawable.face));
        allItems.add(new ItemObject("Kingston Dude", "Ivory Lane, Abuja, Nigeria", R.drawable.face));
        allItems.add(new ItemObject("Edwin Bent", "Johnson Road, Port Harcourt, Nigeria", R.drawable.face));
        allItems.add(new ItemObject("Grace Praise", "Federal Quarters, Abuja Nigeria", R.drawable.face));

        return allItems;
    }
}

Save the file and run your project.

You can download the code for this tutorial below. If you are having hard time downloading the tutorials, kindly contact me.

Remember to subscribe with your email so that you will be among the first to receive our new post once it is published

2 Comments

Add a Comment