CardView is another major element introduced in Material Design. Using CardView you can represent the information in a card manner with a drop shadow (elevation) and corner radius which looks consistent across the platform. CardView extends the FrameLayout and it is supported way back to Android 2.x.

You can achieve good looking UI when CardView is combined with RecyclerView. In this article we are going to learn how to integrate CardView with RecyclerView by creating a beautiful music app that displays music albums with a cover image and title.

android-working-with-cardview-and-recycler-view

How to Add CardView?

To use the CardView in your app, add the CardView dependency in build.gradle and Sync the project.

dependencies {
    // CardView
    compile 'com.android.support:cardview-v7:23.3.+'
}

Add the <android.support.v7.widget.CardView> widget to your layout and place other UI widgets like TextViews, ImageViews inside it. You can notice that the below CardView widget contains a single TextView.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:card_view="http://schemas.android.com/apk/res-auto">

    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_gravity="center"
        android:layout_width="250dp"
        android:layout_height="250dp"
        card_view:cardCornerRadius="4dp">

        <TextView
            android:text="Hello Card"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v7.widget.CardView>

</LinearLayout>

Now let’s see this in action by creating a new project.

1. Creating New Project

1. Create a new project in Android Studio from File ⇒ New Project. When it prompts you to select the default activity, select Empty Activity and proceed.

2. Download this res.zip and add them to your projects res folder. This res folder contains few album covers and icons required for this project.

3. Add the below strings, colors and dimen resources to strings.xml, colors.xml and dimens.xml files.

<resources>
    <string name="app_name">Card View</string>
    <string name="action_settings">Settings</string>
    <string name="action_add_favourite">Add to Favourites</string>
    <string name="action_play_next">Play Next</string>
    <string name="backdrop_title">LOVE MUSIC</string>
    <string name="backdrop_subtitle">This season top 20 albums</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#F50057</color>
    <color name="colorPrimaryDark">#F50057</color>
    <color name="colorAccent">#FF4081</color>
    <color name="viewBg">#f1f5f8</color>
    <color name="album_title">#4c4c4c</color>
</resources>
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="fab_margin">16dp</dimen>
    <dimen name="item_offset">10dp</dimen>
    <dimen name="detail_backdrop_height">250dp</dimen>
    <dimen name="backdrop_title">30dp</dimen>
    <dimen name="backdrop_subtitle">18dp</dimen>
    <dimen name="card_margin">5dp</dimen>
    <dimen name="card_album_radius">0dp</dimen>
    <dimen name="album_cover_height">160dp</dimen>
    <dimen name="album_title_padding">10dp</dimen>
    <dimen name="album_title">15dp</dimen>
    <dimen name="songs_count_padding_bottom">5dp</dimen>
    <dimen name="songs_count">12dp</dimen>
    <dimen name="ic_album_overflow_width">20dp</dimen>
    <dimen name="ic_album_overflow_height">30dp</dimen>
    <dimen name="ic_album_overflow_margin_top">10dp</dimen>
</resources>

4. Open build.gradle and add CardView, RecyclerView and Glide dependencies. RecyclerView is used to display the albums in grid manner. CardView is used to display single album item. Glide is used to display the album cover images.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'

    // RecyclerView
    compile 'com.android.support:recyclerview-v7:23.3.+'

    // CardView
    compile 'com.android.support:cardview-v7:23.3.+'

    // Glide
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

5. To create instance of a single album, we need a model class denoting the album properties like name, number of songs and cover image. So create a class named Album.java and add the below code.

package info.androidhive.cardview;

/**
 * Created by Lincoln on 18/05/16.
 */
public class Album {
    private String name;
    private int numOfSongs;
    private int thumbnail;

    public Album() {
    }

    public Album(String name, int numOfSongs, int thumbnail) {
        this.name = name;
        this.numOfSongs = numOfSongs;
        this.thumbnail = thumbnail;
    }

    public String getName() {
        return name;
    }

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

    public int getNumOfSongs() {
        return numOfSongs;
    }

    public void setNumOfSongs(int numOfSongs) {
        this.numOfSongs = numOfSongs;
    }

    public int getThumbnail() {
        return thumbnail;
    }

    public void setThumbnail(int thumbnail) {
        this.thumbnail = thumbnail;
    }
}

6. We also need an xm layout to display the album card. Create an xml layout named album_card.xml under res ⇒ layout. Here you can notice that I have added <android.support.v7.widget.CardView> and added all the album properties like name, number of songs and cover image inside it. I also added a 3 dot icon which shows a popup menu on tapping it.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_margin="@dimen/card_margin"
        android:elevation="3dp"
        card_view:cardCornerRadius="@dimen/card_album_radius">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/thumbnail"
                android:layout_width="match_parent"
                android:layout_height="@dimen/album_cover_height"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:clickable="true"
                android:scaleType="fitXY" />

            <TextView
                android:id="@+id/title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/thumbnail"
                android:paddingLeft="@dimen/album_title_padding"
                android:paddingRight="@dimen/album_title_padding"
                android:paddingTop="@dimen/album_title_padding"
                android:textColor="@color/album_title"
                android:textSize="@dimen/album_title" />

            <TextView
                android:id="@+id/count"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/title"
                android:paddingBottom="@dimen/songs_count_padding_bottom"
                android:paddingLeft="@dimen/album_title_padding"
                android:paddingRight="@dimen/album_title_padding"
                android:textSize="@dimen/songs_count" />

            <ImageView
                android:id="@+id/overflow"
                android:layout_width="@dimen/ic_album_overflow_width"
                android:layout_height="@dimen/ic_album_overflow_height"
                android:layout_alignParentRight="true"
                android:layout_below="@id/thumbnail"
                android:layout_marginTop="@dimen/ic_album_overflow_margin_top"
                android:scaleType="centerCrop"
                android:src="@drawable/ic_dots" />

        </RelativeLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>

7. Create a menu file named menu_album.xml under res ⇒ menu folder. This menu will be shown as popup menu on tapping on dots icons on each album card item.

8. To render the RecyclerView, we need an adapter class which inflates the album_card.xml by keeping appropriate information. Create a class named AlbumsAdapter.java and add the below content.

package info.androidhive.cardview;

import android.content.Context;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;

import java.util.List;

/**
 * Created by Ravi Tamada on 18/05/16.
 */
public class AlbumsAdapter extends RecyclerView.Adapter<AlbumsAdapter.MyViewHolder> {

    private Context mContext;
    private List<Album> albumList;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, count;
        public ImageView thumbnail, overflow;

        public MyViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.title);
            count = (TextView) view.findViewById(R.id.count);
            thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
            overflow = (ImageView) view.findViewById(R.id.overflow);
        }
    }


    public AlbumsAdapter(Context mContext, List<Album> albumList) {
        this.mContext = mContext;
        this.albumList = albumList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.album_card, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        Album album = albumList.get(position);
        holder.title.setText(album.getName());
        holder.count.setText(album.getNumOfSongs() + " songs");

        // loading album cover using Glide library
        Glide.with(mContext).load(album.getThumbnail()).into(holder.thumbnail);

        holder.overflow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showPopupMenu(holder.overflow);
            }
        });
    }

    /**
     * Showing popup menu when tapping on 3 dots
     */
    private void showPopupMenu(View view) {
        // inflate menu
        PopupMenu popup = new PopupMenu(mContext, view);
        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(R.menu.menu_album, popup.getMenu());
        popup.setOnMenuItemClickListener(new MyMenuItemClickListener());
        popup.show();
    }

    /**
     * Click listener for popup menu items
     */
    class MyMenuItemClickListener implements PopupMenu.OnMenuItemClickListener {

        public MyMenuItemClickListener() {
        }

        @Override
        public boolean onMenuItemClick(MenuItem menuItem) {
            switch (menuItem.getItemId()) {
                case R.id.action_add_favourite:
                    Toast.makeText(mContext, "Add to favourite", Toast.LENGTH_SHORT).show();
                    return true;
                case R.id.action_play_next:
                    Toast.makeText(mContext, "Play next", Toast.LENGTH_SHORT).show();
                    return true;
                default:
            }
            return false;
        }
    }

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

9. Open the layout files main activity activity_main.xml and content_main.xml, add AppBarLayout, CollapsingToolbarLayout, Toolbar and RecyclerView.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/detail_backdrop_height"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleTextAppearance="@android:color/transparent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/backdrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax" />

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:gravity="center_horizontal"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/love_music"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/backdrop_title"
                        android:textColor="@android:color/white"
                        android:textSize="@dimen/backdrop_title" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/backdrop_subtitle"
                        android:textColor="@android:color/white"
                        android:textSize="@dimen/backdrop_subtitle" />

                </LinearLayout>
            </RelativeLayout>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

</android.support.design.widget.CoordinatorLayout>

content_main.xml

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/viewBg"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="info.androidhive.cardview.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:clipToPadding="false"
        android:scrollbars="vertical" />

</RelativeLayout>

10. Finally open MainActivity.java and do the necessary changes.

> initCollapsingToolbar() – Shows or hides the toolbar title when the toolbar is collapsed or expanded.

> prepareAlbums() – Adds sample albums data required for the recycler view.

> GridLayoutManager is used to display the RecyclerView in Grid manner instead of list.

> GridSpacingItemDecoration is used to give equal margins around RecyclerView grid items.

> AlbumsAdapter instance is created and assigned to RecyclerView which renders the CardView albums in grid fashion.

package info.androidhive.cardview;

import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;

import com.bumptech.glide.Glide;

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

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private AlbumsAdapter adapter;
    private List<Album> albumList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        initCollapsingToolbar();

        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        albumList = new ArrayList<>();
        adapter = new AlbumsAdapter(this, albumList);

        RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(10), true));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(adapter);

        prepareAlbums();

        try {
            Glide.with(this).load(R.drawable.cover).into((ImageView) findViewById(R.id.backdrop));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Initializing collapsing toolbar
     * Will show and hide the toolbar title on scroll
     */
    private void initCollapsingToolbar() {
        final CollapsingToolbarLayout collapsingToolbar =
                (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle(" ");
        AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
        appBarLayout.setExpanded(true);

        // hiding & showing the title when toolbar expanded & collapsed
        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            boolean isShow = false;
            int scrollRange = -1;

            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (scrollRange == -1) {
                    scrollRange = appBarLayout.getTotalScrollRange();
                }
                if (scrollRange + verticalOffset == 0) {
                    collapsingToolbar.setTitle(getString(R.string.app_name));
                    isShow = true;
                } else if (isShow) {
                    collapsingToolbar.setTitle(" ");
                    isShow = false;
                }
            }
        });
    }

    /**
     * Adding few albums for testing
     */
    private void prepareAlbums() {
        int[] covers = new int[]{
                R.drawable.album1,
                R.drawable.album2,
                R.drawable.album3,
                R.drawable.album4,
                R.drawable.album5,
                R.drawable.album6,
                R.drawable.album7,
                R.drawable.album8,
                R.drawable.album9,
                R.drawable.album10,
                R.drawable.album11};

        Album a = new Album("True Romance", 13, covers[0]);
        albumList.add(a);

        a = new Album("Xscpae", 8, covers[1]);
        albumList.add(a);

        a = new Album("Maroon 5", 11, covers[2]);
        albumList.add(a);

        a = new Album("Born to Die", 12, covers[3]);
        albumList.add(a);

        a = new Album("Honeymoon", 14, covers[4]);
        albumList.add(a);

        a = new Album("I Need a Doctor", 1, covers[5]);
        albumList.add(a);

        a = new Album("Loud", 11, covers[6]);
        albumList.add(a);

        a = new Album("Legend", 14, covers[7]);
        albumList.add(a);

        a = new Album("Hello", 11, covers[8]);
        albumList.add(a);

        a = new Album("Greatest Hits", 17, covers[9]);
        albumList.add(a);

        adapter.notifyDataSetChanged();
    }

    /**
     * RecyclerView item decoration - give equal margin around grid item
     */
    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

        private int spanCount;
        private int spacing;
        private boolean includeEdge;

        public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
            this.spanCount = spanCount;
            this.spacing = spacing;
            this.includeEdge = includeEdge;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view); // item position
            int column = position % spanCount; // item column

            if (includeEdge) {
                outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }
        }
    }

    /**
     * Converting dp to pixel
     */
    private int dpToPx(int dp) {
        Resources r = getResources();
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }
}

If you run the app now, you can see the album CardViews displayed in a grid.

android-integrating-cardview-and-recyclerview-music-app
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
  • Shourya Rastogi

    how to use recycler view with firebase to show images and text in a 2 column grid..plz help

  • Abdul Rehman

    sir can u tell that when we click on one item and onclick a new detailed activty is open with larger image and full details of card views plz give any perfect tutorial link thanks to androidhive admins

  • Excelente!

  • Mitchell Chen

    Very much appreciated for your excellent example.

  • Guruprasad M Anweri

    When i import your project i am facing ProcessNotCreated exception any help here.. i am completely new to Android

  • Chihab Chihab

    Thank you for the work you do

    Ravi Tamada

    Happy to be among you

    • Chihab Chihab

      Happy to be among you

      • You are welcome 🙂

        • Chihab Chihab

          I am a fan of Indian Kitchen

          I send you a proposal a project
          please reply me I know you have a lot of work but try to see

          thank you
          धन्यवाद

        • Chihab Chihab

          Reply me for the project I send
          thank you

  • Bhavik Shah

    first of all thank you very much for a simple explanation of cardlayout, but what if I want to know which card/position menu is clicked?

  • Chihab Chihab

    I am a fan of Indian Kitchen

    I send you a proposal a project
    please reply me I know you have a lot of work but try to see

    thank you
    धन्यवाद

  • Ravi Rajput

    Bhai good going… Thanks for you usefull tuts 👌

  • M Shariq Khan

    Hello sir nice tutorial. I am using card layout and wanted to give some background color. It works for above level 21 but doesnt works fine for the below ones. I am using both properties android:background=”@color/ darkgreen” android:cardBackgroundColor=”@color/darkgreen”. Any help @Ravi Tamada? Thanks.

    • If it’s not working, place another layout (Ex: LinearLayout) inside cardview and give background color to that layout. If you want to get the ripple effect on the card, use android:foreground="?attr:selectableItemBackground" for the layout added.

  • Nitish Sharma

    hello Ravi..
    Can you let me know how to add Click Listener on Image which are showing using cardview and recycleview..

    • You have to write click listener in adapter class and send the callback to activity via interface.

      Try the below code.

      package info.androidhive.cardview;

      import android.content.Context;
      import android.support.v7.widget.CardView;
      import android.support.v7.widget.PopupMenu;
      import android.support.v7.widget.RecyclerView;
      import android.view.LayoutInflater;
      import android.view.MenuInflater;
      import android.view.MenuItem;
      import android.view.View;
      import android.view.ViewGroup;
      import android.widget.ImageView;
      import android.widget.TextView;
      import android.widget.Toast;

      import com.bumptech.glide.Glide;

      import java.util.List;

      /**
      * Created by Ravi Tamada on 18/05/16.
      */
      public class AlbumsAdapter extends RecyclerView.Adapter {

      private Context mContext;
      private List albumList;
      private AlbumsAdapterListener listener;

      public class MyViewHolder extends RecyclerView.ViewHolder {
      public TextView title, count;
      public ImageView thumbnail, overflow;
      public CardView cardView;

      public MyViewHolder(View view) {
      super(view);
      title = view.findViewById(R.id.title);
      count = view.findViewById(R.id.count);
      thumbnail = view.findViewById(R.id.thumbnail);
      overflow = view.findViewById(R.id.overflow);
      cardView = view.findViewById(R.id.card_view);
      }
      }

      public AlbumsAdapter(Context mContext, List albumList, AlbumsAdapterListener listener) {
      this.mContext = mContext;
      this.albumList = albumList;
      this.listener = listener;
      }

      @Override
      public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      View itemView = LayoutInflater.from(parent.getContext())
      .inflate(R.layout.album_card, parent, false);

      return new MyViewHolder(itemView);
      }

      @Override
      public void onBindViewHolder(final MyViewHolder holder, final int position) {
      Album album = albumList.get(position);
      holder.title.setText(album.getName());
      holder.count.setText(album.getNumOfSongs() + ” songs”);

      // loading album cover using Glide library
      Glide.with(mContext).load(album.getThumbnail()).into(holder.thumbnail);

      holder.overflow.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
      showPopupMenu(holder.overflow, position);
      }
      });

      holder.cardView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
      listener.onCardSelected(position, holder.thumbnail);
      }
      });

      holder.thumbnail.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
      listener.onCardSelected(position, holder.thumbnail);
      }
      });
      }

      /**
      * Showing popup menu when tapping on 3 dots
      */
      private void showPopupMenu(View view, int position) {
      // inflate menu
      PopupMenu popup = new PopupMenu(mContext, view);
      MenuInflater inflater = popup.getMenuInflater();
      inflater.inflate(R.menu.menu_album, popup.getMenu());
      popup.setOnMenuItemClickListener(new MyMenuItemClickListener(position));
      popup.show();
      }

      /**
      * Click listener for popup menu items
      */
      class MyMenuItemClickListener implements PopupMenu.OnMenuItemClickListener {

      int position;

      public MyMenuItemClickListener(int position) {
      this.position = position;
      }

      @Override
      public boolean onMenuItemClick(MenuItem menuItem) {
      switch (menuItem.getItemId()) {
      case R.id.action_add_favourite:
      listener.onAddToFavoriteSelected(position);
      return true;
      case R.id.action_play_next:
      listener.onPlayNextSelected(position);
      return true;
      default:
      }
      return false;
      }
      }

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

      public interface AlbumsAdapterListener {
      void onAddToFavoriteSelected(int position);

      void onPlayNextSelected(int position);

      void onCardSelected(int position, ImageView thumbnail);
      }
      }

      • Nitish Sharma

        ok ..but where you define cardView = view.findViewById(R.id.card_view in your activity file and
        in void onCardSelected(int position, ImageView thumbnail how we know that which image is clicked and what action should be perform on that..

  • mattia rogledi

    Hi Ravi! thank you for the tutorial, but my scrolling isn’t smooth, can i ask why?

    • Disable nested scrolling on recyclerview if you are using NestedScrollView.

      recyclerView.setNestedScrollingEnabled(false);

      • Bilawal

        @ravi8x:disqus Sir aap Best ho..!! Thankyou Androidhive

  • Rahul Verma

    send me compete geofence source code in android,when i am going some places notify alarm

  • RR

    Thanks for great tutorial. Could you please tell me how this code would behave in landscape mode? how can I show 3 or more columns based on device width in landscape mode?

  • Hisham Hummadi

    Hi,
    Thanks for the awesome tutorial, I would like to ask you how to add click listener to each album and open new activity?

  • AndroidHive Student

    I clicked download and now the code is downloaded 46,500 times. Good Work Android Hive. <3 you.

    • Thank You. There are other downloads which are more than 3Lakhs 😀

  • Mark Raishbrook

    Really helpful code. Thank you! Just one question. Why do you use Glide to load the images instead of just using setImageResource() on the ImageView?

    • setImageResource takes an image from the project’s drawable folder. As the image is there on Internet, we need to use Glide to load the images.

  • Set NoActionBar theme for this activity in manifest file or remove the AppBar / Toolbar from the activity layout.

    • cheikhouna gueye

      Thank you I solved the problem by following your advice (Set NoActionBar theme for this activity in manifest file )

  • Deb Chatterjee

    Hi Ravi, I just want to add functionality to each and every Card view differently. Means If I click on first Card View, a song will play and on the Sec card view, will play another. How can I do so?

    • Do you have an activity that will play a song?

  • Pourya Mohammadpoor

    hi sir and so much thanks for this great material design tutorial
    i have a question and that is how can we show a spicific folder contents in card views?
    for example folder named pictures in sd card
    any help wil greatly appreciated

    • You can create an activity that will read pictures of a folder from sd card. On clicking the CardView, you can pass the folder path of sd card to this activity and display the images.

      • Pourya Mohammadpoor

        hey sir sorry for annoyance but im new in android studio and don’t know much about strings, if its simple can you please show me how with code?
        again thanks in advance

        • What do you want to know about strings? You mean strings.xml?

          • Pourya Mohammadpoor

            no no i want what i wanted before show contents from a folder (for example pictures,etc) in card view
            as im a begginer so i couldnt done what you told about listing contents in a activity and pass the folder path
            can you show me with code?
            ps; i though we have to define the path using string that’s because i said about strings

  • Mukul Bagre

    Hi Ravi. I wanted to know a way to make each card completely fill the horizontal space rather than two cards sharing the space. How can that be done? Thanks in advance.

    • In the MainActivity, GridLayoutManager(this, 2) is used as Layout Manager. Here 2 is number of columns. You can make it 1 or use LinearLayout manager instead. You also need to adjust your ImageView aspect ratio.

  • Samsung VS Iphone

    sir hum tabbed activity k sath kese jin kr skte hain isko.

  • Keima

    How can i get to another activity if i click for example the item in onMenuItemClickListener? Thanks

    • Do you know the code to launch an activity?

      • Keima

        yes. but it has error…

        Intent intent = new Intent(AlbumsAdapter.this, Download.class);
        startActivity(intent);

        I think what keeping it error is that my extends recyclerview adapter and appcompatactivity is not compatible

        • Instead of AlbumsAdapter.this, use mContext.

          Intent intent = new Intent(mContext, Download.class);

          • Keima

            But its not opening the Download.class . Im new to android. please help me
            🙁

          • Keima

            I use this. But it has error. The app keeps on stopping…

            intent = new Intent(mContext, Web.class);
            mContext.startActivity(intent);

          • What was the error when it crashed?

          • Keima

            Open app again…

          • Connect your device using USB, open LogCat in Android Studio. When the app crashes, the error will be printed in LogCat.

          • Keima
          • This is not the error but don’t worry you will learn on the go. Explore more about app debugging and LogCat.

          • Keima

            Ok. Appreciate it man. Thanks so much. 🙂

          • You are welcome. Let me know once you solve the problem.

      • Keima

        Can you show me how?. Thanks

      • Bonza

        If you want to launch another activity by clicking the image on the card, do you handle the onclicklister from the adapter class or on the mainactivity class?

        • You can do it in both ways. The click listener assigned in adapter when you want to detect click on different elements. Ex: text, image etc., But if you want to detect the just the row click, writing the listener in main activity is good choice.

  • Arwen Ghafur

    hello @ravi8x:disqus when i run the app it said that card view has stoped why ???!!!1

    • Check the LogCat for errors while the app is crashing.

  • Keima

    Good day @ravi8x:disqus . Unfortunately, I still cant find to when i click the item in the 3 dots i cant go to another page or another activity. Please help

    https://uploads.disquscdn.com/images/a1c56bf44258e7e66ce7416c37c44c4137a8bf19ee8148f7a09df7e2385d48c2.png

  • RK RJ studio

    I’m trying to implement on click listeners for each card view which shows different activity. but it is showing the same activity.
    This is what i have tried to implement.

    public MyViewHolder(View v) {
    super(v);
    view = v;
    title = (TextView) view.findViewById(R.id.title);
    count = (TextView) view.findViewById(R.id.count);
    thumbnail = (ImageView) view.findViewById(R.id.thumbnail);

    view.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
    Intent intent = new Intent(view.getContext(),FirstActivity.class);
    view.getContext().startActivity(intent);
    }
    });
    }

    Please explain how to show SecondActivity on clicking second cardview.

    • Hi RK

      The way you are doing currently is correct. Normally all the click events will launch the same activity by passing necessary data via intents. In this case, an id or name (some unique identification of each card) will be sent to next activity. You need to take appropriate action depending on the id.

      The way you are thinking (creating new activity for each card) is wrong as you shouldn’t create 100 activities if there are 100 cards.

      • RK RJ studio

        Thanks for replying .
        Actually I sorted it out yesterday only by using switch statements cases to open activities.
        But the way using id will save more data in app.
        It was great tutorial and anyways.
        I’ll try to post my code here which worked perfectly for me.

  • Deb Chatterjee

    @ravi8x:disqus Can you please Help me about this problem? Am I have to use Switch Case?

    • Do the following.

      1. When a card is selected, send the file name to another activity.

      2. Create an activity which plays a song. The song file name will be read from Intent sent from cards grid activity.

      Refer this article to know how to send data to another activity via intents.
      https://www.androidhive.info/2011/10/android-listview-tutorial/

      • Deb Chatterjee

        Ok done, but I can not play different songs, Just one song is playing when I select any card? How Can I play different songs from Different Cards?

  • FAIL CODE

    Sorry to say , your code is so messed up, i keep having the error :
    Attempt to invoke virtual method ‘void android.support.design.widget.CollapsingToolbarLayout.setTitle(java.lang.CharSequence)’ on a null object reference

    Why u wanna make the toolbar so complex ? any messed up with everything, i tried to change the toolbar, try to remove it, it just cant work. Please next time check ur code before upload it up !

    • SORRY BRO

      Sorry its works now , my fault , my stupid mistakes, thanks alot for your code, im so sorry, i apologize , you done a great job !!!

  • Aminos Waray

    Hi, Thank you for all the tutorials.
    I tried to use what’s in this to to update my recyclerview. It worked, but i want to change number of items per row. How to do that, as you give for example “2” as spancount to the GridLayoutManager ? Thanks again

    • Yes 2 is the number of columns. You can change that number to whatever number of items you want.

  • RK RJ studio

    @James
    Implement your OnClickListeners in class MyViewHolder()
    Let’s Assume you have two CardViews which opens has different activities, use this code which worked for me.

    view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    switch (getAdapterPosition()) {
    case 0:
    Intent firstIntent= new
    Intent(view.getContext(),com.example.android.YourApp.FirstActivity.class);
    view.getContext().startActivity(firstIntent);
    break;
    case 1:
    Intent secondIntent = new
    Intent(view.getContext(),com.example.android.YourApp.SecondActivity.class);
    view.getContext().startActivity(secondIntent);
    break;

    Similarly you can increase number of cases based on number of cards you use.
    You can also achieve this by using id’s for different acivities.