RecyclerView & CardView on Android

Learning on how to make a custom layout animation in Android

(Notes are taken from various other blogs)

  • RecyclerViews use layout manager that determines when list items are no longer visible and can be reused.
  • There are a few different default types we can use, and we can also create custom ones if needed.

→ Creating a CardView

A Cardview is a ViewGroup. Like other ViewGroup, can be added to the layout XML.

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

Place the CardView in a LinearLayout in the XML. The CardView represent different multimedia apps.

  • A TextView to display the name of the app
  • A TextView to display the App’s description
  • An ImageView to Display the App’s photo
<?xml version="1.0" encoding="utf-8"?>

<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:layout_width="match_parent"
android:layout_height="match_parent"
>

<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/app_photo"
android:layout_alignParentLeft = "true"
android:layout_alignParentTop = "true"
android:layout_marginRight="16dp"
>
</ImageView>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/person_name"
android:layout_toRightOf="@+id/app_photo"
android:layout_alignParentTop="true"
android:textSize="30sp"
/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/person_age"
android:layout_toRightOf="@+id/app_photo"
android:layout_below="@+id/person_name"
>
</TextView>
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

→ Creating a RecyclerView

I. Define it in a layout

<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="368dp"
android:layout_height="495dp"
tools:layout_editor_absoluteY="8dp"
tools:layout_editor_absoluteX="8dp"
/>

To use this in the Activity

private RecyclerView mRecyclerView;
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

Everyone sets this to true to improve performance, indicating that the size of the recycle View won’t be changing

mRecyclerView.setHasFixedSize(true);

II. Using a LayoutManager

Unlike a ListView, a RecyclerView needs a LayoutManager to manage the positioning of it’s items.

LayoutManager can bedefined by extending RecyclerView.LayoutManager class.

There are predefined LayoutManager subclasses as well:

  • LinearLayoutManager
  • GridLayoutManager
  • StaggeredGridLayoutManager

Will use a LinearLayoutManager, in other notes will make a custom LayoutManager

// Use a linear Layout Manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);

III Defining the Data

An Adapter is needed to access it’s data, just like a ListView.

Create a class to represent an App and then write a method to initialize a List of Apps objects.

public class App {
String name;
String description;
int photoId;
App(String name, String description, int photoId){
this.name = name;
this.description = description;
this.photoId = photoId;
}
private List<App> apps;
void initializeData() {
apps = new ArrayList<>();
apps.add(new App("Movies", "Contains movies to watch", R.drawable.movies));
apps.add(new App("Music", "Contains music to listen", R.drawable.movies));
apps.add(new App("Games", "Contains Games to play", R.drawable.games));

}
};

IV Creating an Adapter

Adapter needs to extend RecyclerView.Adapter

This Adapter follows ViewHolder design pattern.

A class that extends RecyclerView.ViewHolder, minimizes the number of calls to costly findViewById method.

Initailize the views that belong to the items of our RecyclerView

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.AppViewHolder> {
private String[] mDataset;

// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class AppViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
CardView mCardView;
TextView name;
TextView description;
ImageView photoId;

public AppViewHolder(View itemView) {
super(itemView);
mCardView = (CardView) itemView.findViewById(R.id.cv);
name = (TextView) itemView.findViewById(R.id.app_name);
description = (TextView) itemView.findViewById(R.id.app_description);
photoId = (ImageView) itemView.findViewById(R.id.app_photo);
}
}

}

Add a suitable constrcutor so that it has a handle to the data that the RecyclerView displays.

List<App> mApps;
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(List<App> mApps){
this.mApps = mApps;
}

RecyclerView.Adapter has three abstract methods that must override.

  • onCreateViewHolder()
  • onBindViewHolder()
  • getItemCount()

onCreateViewHolder

  • Called when ViewHolder needs to be initialized.
  • Specifies the layout that each item of the RecyclerView should use.
  • Done by inflating the layout using LayoutInflater, passing the ouput to the constructor of the custom ViewHolder
// Create new views (invoked by layout manager)
@Override
public AppViewHolder onCreateViewHolder(ViewGroup parent, int viewType){

// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview, parent, false);
// set the view's size, margins, paddings and layout parameters
AppViewHolder vh = new AppViewHolder(v);
return vh;
}

onBindViewHolder

  • Override to specify the contents of each item of the RecyclerView.
  • Similar to getView method of a ListView’s adapter.
  • Set the values of the name, description and photo fields of the CardView.
// Replace the contents of a view (invoked by layout manager)
@Override
public void onBindViewHolder(AppViewHolder holder, int position){
// - get element from your dataset at this position.
// - replace the contents of the view with that element.
holder.name.setText(mApps.get(position).name);
holder.description.setText(mApps.get(position).description);
holder.photoId.setImageResource(mApps.get(position).photoId);
}

getItemCount

  • Should return the number of item present in the data.
  • Our data is list, so calling size() method should suffice.
//Return the size of your dataset (invoked by layout manager)
@Override
public int getItemCount(){
return mApps.size();
}