The recycler view replaces the good old list view. It provides more flexibility in how the elements of a list are shown, for example, as a grid and as horizontal or vertical items. Instead of rows, we can now choose to display cards wherever it is suitable.
In our app, each card should display some text about the entry and a thumbnail of the picture that we took. This is what this recipe will be all about.
To go through this recipe, you need to have Android up and running. Also make sure that you have installed the latest SDK. (You can check whether you have the latest SDK by opening the SDK manager). To do so, open the Tools menu, choose Android, and next, choose the SDK Manager option.
Let's investigate, using the following steps, how to use recycler views and cards:
WaterApp
and enter packtpub.com
in the Company Domain field. Then, click on the Next button.build.gradle
file within your app
folder and add the dependency for the recycler view to the dependencies
section as shown in the following code:dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.1.1' compile 'com.android.support:recyclerview-v7:+' }
minSdkVersion
to at least 21
in the build.gradle
file.build.gradle
file, or in case it does not, click on the Sync Project with Gradle files button on the toolbar.activity_main.xml
layout file, remove the Hello World TextView
, and add a RecyclerView
tag to the layout, like this:<android.support.v7.widget.RecyclerView android:id="@+id/main_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"/>
MainActivity
class, add the following to the onCreate
method just after setContentView
:RecyclerView recyclerView = (RecyclerView) findViewById(R.id.main_recycler_view);
RecyclerView
class is not a known class yet. Use the Alt + Enter shortcut to add the right import statement or add the following line yourself:import android.support.v7.widget.RecyclerView;
LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager);
models
, and within this package, create a new Drink
class as follows:package com.packt.waterapp.models;import java.util.Date; public class Drink { public Date dateAndTime; public String comments; public String imageUri; }
Here, the Date
class refers to the java.util.Date
package (this is specified since there is also a SQL-related class with the same class name).
layout
package in the project tree and create a new resource file. To do so, choose New and New Layout Resource File from the menu. Name it adapter_main.xml
and hit the OK button.LinearLayout
from vertical
to horizontal
, add some padding to it and add an image view to it, as shown in the following snippet. We will also add a default image so that we have something to look at:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal" android:layout_width="match_parent" android:padding="8dp" android:layout_height="match_parent"> <ImageView android:id="@+id/main_image_view" android:src="@android:drawable/ic_menu_camera" android:scaleType="center" android:layout_width="90dp" android:layout_height="90dp" /> </LinearLayout>
TextView
widgets wrapped in another LinearLayout
widget. Add these after the ImageView
tag:<LinearLayoutandroid:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/main_date_time_textview" android:layout_marginTop="8dp" android:textSize="12sp" android:textColor="@color/material_blue_grey_800" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/main_comment_textview" android:layout_marginTop="16dp" android:maxLines="3" android:textSize="16sp" android:textColor="@color/material_deep_teal_500" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
adapters
. Within that package, create the MainAdapter
class that will be using a ViewHolder
class, helping us to display the data exactly where we want it to appear. We also include all methods that need to be overridden such as the onBindViewHolder
method and the getItemCount
method:public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> { private ArrayList<Drink> mDrinks;private Context mContext;public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mCommentTextView; public TextView mDateTimeTextView; public ImageView mImageView; public ViewHolder(View v) { super(v); } } public MainAdapter(Context context, ArrayList<Drink> drinks) { mDrinks = drinks; mContext = context; } @Override public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from( parent.getContext()).inflate( R.layout.adapter_main, parent, false); ViewHolder viewHolder = new ViewHolder(v); viewHolder.mDateTimeTextView = (TextView)v.findViewById( R.id.main_date_time_textview); viewHolder.mCommentTextView = (TextView)v.findViewById( R.id.main_comment_textview); viewHolder.mImageView = (ImageView)v.findViewById( R.id.main_image_view); return viewHolder; } @Override public int getItemCount() { return mDrinks.size(); } }
onBindViewHolder
method and add the implementation to actually bind the data to the right widgets:@Override public void onBindViewHolder(ViewHolder holder,int position) { Drink currentDrink = mDrinks.get(position); holder.mCommentTextView.setText( currentDrink.comments); holder.mDateTimeTextView.setText( currentDrink.dateAndTime.toString()); if (currentDrink.imageUri != null){ holder.mImageView.setImageURI( Uri.parse(currentDrink.imageUri)); } }
MainActivity
file, we need to have an instance of the adapter and some data to display. Add a private adapter and a private array list containing the Drink
items:private MainAdapter mAdapter;private ArrayList<Drink> mDrinks;
onCreate
method, tell recyclerView
which adapter to use and tell the adapter which dataset to use:mAdapter = new MainAdapter(this, mDrinks); recyclerView.setAdapter(mAdapter);
MainActivity
file, we want to add some dummy data so that we have some idea about what things are going to look like. Add the following to the onCreate
method just before the part where we create the MainAdapter
class:mDrinks = new ArrayList<Drink>(); Drink firstDrink = new Drink(); firstDrink.comments = "I like water with bubbles most of the time..."; firstDrink.dateAndTime = new Date(); mDrinks.add(firstDrink);Drink secondDrink = new Drink(); secondDrink.comments = "I also like water without bubbles. It depends on my mood I guess ;-)"; secondDrink.dateAndTime = new Date(); mDrinks.add(secondDrink);
Import the required packages using the Alt + enter shortcut.
Run your app to verify that everything has gone well so far. Your app will display two entries containing the sample data that we have created in the previous step.
The app looks okay but I would not want to call it beautiful yet. Let's see if we can improve this a little. The following steps will help us to create the app using card views:
build.gradle
file in the app
folder and add a CardView
dependency, just after the one for the recycler view:compile 'com.android.support:cardview-v7:+'
And synchronize your project again.
By the way, if this app was for real, then avoid unpleasant surprises by specifying an exact version instead of using the +
sign in the version number for any dependency your app may have. Currently, this is 21.0.0
for this particular dependency, but By the time you read this, a new version might be available.
adapter_main_card_view.xml
. Add some padding to the LinearLayout
tag and within the linear layout
tag, add a CardView
:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:padding="4dp" android:layout_height="match_parent"> <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="match_parent" android:layout_height="wrap_content"card_view:cardCornerRadius="4dp"></android.support.v7.widget.CardView> </LinearLayout>
adapter_main.xml
file, copy ImageView
and the two TextView
widgets (but not LinearLayout
that contains the two TextView
widgets) and paste them within CardView
that you have added to the adapter_main_card_view.xml
file.CardView
behaves as if it is FrameLayout
, you need to set the margins for the text labels. Add a left margin to both text views. Also modify the top margin for the TextView
comment:<TextView android:id="@+id/main_date_time_textview" android:layout_marginTop="8dp" android:layout_marginLeft="100dp" android:textSize="12sp" android:textColor="@color/material_blue_grey_800" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/main_comment_textview" android:layout_marginTop="32dp" android:layout_marginLeft="100dp" android:maxLines="3" android:textSize="16sp" android:textColor="@color/material_deep_teal_500" android:layout_width="match_parent" android:layout_height="wrap_content" />
MainAdapter
class to use this layout by changing the layout ID in the onCreateViewHolder
method:View v = LayoutInflater.from(parent.getContext()). inflate(R.layout.adapter_main_card_view, parent, false);
Run the app again and we will see what it will look like this time:
There is a lot of documentation about material design. Browse through the various examples that are available on various websites, such as https://www.materialup.com, http://materialdesignblog.com or http://material-design.tumblr.com.
Or, download some of the material designed apps that are available in the Play Store, such as the Inbox, Google+, Wunderlist, Evernote, LocalCast, and SoundCast apps.