Android RecyclerView and Android CardView got introduced in Android Lollipop with Material Design. For those who’re not aware of Material Design, its a comprehensive guide of UI Widgets introduced since Android 5.0 and it improves the visual appeal of the apps.
Android RecyclerView
Android RecyclerView is a more advanced, powerful and flexible version of the ListView. Android RecyclerView is similar to ListView except that it forces us to use RecyclerView.ViewHolder class to hold the elements which is not a compulsion in ListView.
As the name suggests, anrdoid RecyclerView is used to reuse cells when scrolling up and down by recycling the items in the list. Another improvement in RecyclerView is that it allows us to set theLayoutManagers dynamically at runtime unlike the ListView which was only available in a Vertical scrolling List. RecyclerView allows us to set the following types of Layouts at runtime.
- LinearLayoutManager : it supports both vertical and horizontal lists
- StaggeredLayoutManager : it supports staggered lists
- GridLayoutManager : it supports displaying grids as seen in GalleryView earlier
Android RecyclerView Classes
- The RecyclerView.ItemAnimator class provides better support to animating the views unlike the ListViews
- The RecyclerView.ItemDecorator class provides better support when it comes to adding borders and dividers thereby giving huge control to us
Hence a RecyclerView is more customisable when compared to ListView and gives greater control to the users.
The RecyclerView is available in the support library. So we need to modify our gradle script to add the following dependency.
The RecyclerView is available in the support library. So we need to modify our gradle script to add the following dependency.
dependencies { compile 'com.android.support:recyclerview-v7:21.0.0-rc1' }
Android CardView
Android CardView UI component shows information inside cards. This component is generally used to show contact information. This component is available in another support library so we have to add its dependency too.
dependencies { compile 'com.android.support:cardview-v7:21.0.0-rc1' compile 'com.android.support:recyclerview-v7:21.0.0-rc1' }
Android CardView widget allows us to control the background color, shadow, corner radius, elevation etc. For using the custom attributes in XML, we need to add the following namespace declaration to the parent layout. Following is the namespace declaration with some attributes from our project.
<android.support.v7.widget.CardView android:id="@+id/card_view" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" card_view:cardBackgroundColor="@color/grey_300" card_view:cardCornerRadius="10dp" card_view:cardElevation="5dp" card_view:cardUseCompatPadding="true">
The important attributes used above are:
- card_view:cardCornerRadius : Used to set the corner radius in our layouts
- card_view:cardBackgroundColor : Used to set the background color of the view
In our example project, we’ll add a RecyclerView to display a list of CardViews that contains Android Version Names and Numbers along with a sample logo. The CardView
onclick
is programmed to remove that Card from the list. We’ve added a menu option in the ActionBar to add back the removed cards in order.
Note : The logo images are taken at random from google. So sizes would vary.
Android RecyclerView and CardView Example
The project consists of a
MainActivity
that displays the RecyclerView
. The CardView is added to the RecyclerView from the CustomAdapter class. The DataModel is used to retrieve the data for each CardView through getters. The MyData class holds the arrays of textviews and drawables along with their ids.Android RecyclerView and CardView Example Code
The
activity_main.xml
holds the RecyclerView inside a RelativeLayout as shown below.
activity_main.xml code:
<RelativeLayout 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: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:background="@color/grey_300" > <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" /> </RelativeLayout>
Android CardView layout is defined below:
cards_layout.xml code:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:tag="cards main container"> <android.support.v7.widget.CardView android:id="@+id/card_view" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" card_view:cardBackgroundColor="@color/color_white" card_view:cardCornerRadius="10dp" card_view:cardElevation="5dp" card_view:cardUseCompatPadding="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:id="@+id/imageView" android:tag="image_tag" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:src="@drawable/ic_launcher"/> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:layout_weight="2" android:orientation="vertical" > <TextView android:id="@+id/textViewName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="10dp" android:text="Android Name" android:textAppearance="?android:attr/textAppearanceLarge"/> <TextView android:id="@+id/textViewVersion" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="10dp" android:text="Android Version" android:textAppearance="?android:attr/textAppearanceMedium"/> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout>
Android CardView holds an ImageView along with two TextViews in a Nested Linear Layout. The
menu_main.xml
contains a single item to add back the cards removed.
menu_main.xml code:
<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/add_item" android:title="Add" android:orderInCategory="100" app:showAsAction="always"/> </menu>
The
MainActivity.java
class is defined below :package com.recyclerviewcardview; import android.content.Context; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private static RecyclerView.Adapter adapter; private RecyclerView.LayoutManager layoutManager; private static RecyclerView recyclerView; private static ArrayList<DataModel> data; static View.OnClickListener myOnClickListener; private static ArrayList<Integer> removedItems; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myOnClickListener = new MyOnClickListener(this); recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); recyclerView.setHasFixedSize(true); layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); data = new ArrayList<DataModel>(); for (int i = 0; i < MyData.nameArray.length; i++) { data.add(new DataModel( MyData.nameArray[i], MyData.versionArray[i], MyData.id_[i], MyData.drawableArray[i] )); } removedItems = new ArrayList<Integer>(); adapter = new CustomAdapter(data); recyclerView.setAdapter(adapter); } private static class MyOnClickListener implements View.OnClickListener { private final Context context; private MyOnClickListener(Context context) { this.context = context; } @Override public void onClick(View v) { removeItem(v); } private void removeItem(View v) { int selectedItemPosition = recyclerView.getChildPosition(v); RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForPosition(selectedItemPosition); TextView textViewName = (TextView) viewHolder.itemView.findViewById(R.id.textViewName); String selectedName = (String) textViewName.getText(); int selectedItemId = -1; for (int i = 0; i < MyData.nameArray.length; i++) { if (selectedName.equals(MyData.nameArray[i])) { selectedItemId = MyData.id_[i]; } } removedItems.add(selectedItemId); data.remove(selectedItemPosition); adapter.notifyItemRemoved(selectedItemPosition); } } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); if (item.getItemId() == R.id.add_item) { //check if any items to add if (removedItems.size() != 0) { addRemovedItemToList(); } else { Toast.makeText(this, "Nothing to add", Toast.LENGTH_SHORT).show(); } } return true; } private void addRemovedItemToList() { int addItemAtListPosition = 3; data.add(addItemAtListPosition, new DataModel( MyData.nameArray[removedItems.get(0)], MyData.versionArray[removedItems.get(0)], MyData.id_[removedItems.get(0)], MyData.drawableArray[removedItems.get(0)] )); adapter.notifyItemInserted(addItemAtListPosition); removedItems.remove(0); } }
The
removeItems()
method is invoked from the listener method to remove the CardView clicked. Its respective id is stored in an array to retrieve later. To add the view later we've implemented another method named addRemovedItemToList()
. In this method we add that view at a predefined position in the list and remove its id from the removedItems
array. The CustomAdapter is notified in both the cases.
The CustomerAdapter.java class is defined below :
package com.recyclerviewcardview; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> { private ArrayList<DataModel> dataSet; public static class MyViewHolder extends RecyclerView.ViewHolder { TextView textViewName; TextView textViewVersion; ImageView imageViewIcon; public MyViewHolder(View itemView) { super(itemView); this.textViewName = (TextView) itemView.findViewById(R.id.textViewName); this.textViewVersion = (TextView) itemView.findViewById(R.id.textViewVersion); this.imageViewIcon = (ImageView) itemView.findViewById(R.id.imageView); } } public CustomAdapter(ArrayList<DataModel> data) { this.dataSet = data; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.cards_layout, parent, false); view.setOnClickListener(MainActivity.myOnClickListener); MyViewHolder myViewHolder = new MyViewHolder(view); return myViewHolder; } @Override public void onBindViewHolder(final MyViewHolder holder, final int listPosition) { TextView textViewName = holder.textViewName; TextView textViewVersion = holder.textViewVersion; ImageView imageView = holder.imageViewIcon; textViewName.setText(dataSet.get(listPosition).getName()); textViewVersion.setText(dataSet.get(listPosition).getVersion()); imageView.setImageResource(dataSet.get(listPosition).getImage()); } @Override public int getItemCount() { return dataSet.size(); } }
In the above code we've implemented our own ViewHolder by extending RecyclerView.ViewHolder. The view is inflated from the
cards_layout.xml
which we had defined in the layouts directory. The onClickListener in the MainActivity is attached to this view in the below snippet.view.setOnClickListener(MainActivity.myOnClickListener);
An ArrayList stores all the datas in the form of a DataModel class object in an ArrayList and adds them to the respective cards in the list.
The
DataModel.java
and MyData.java
class which contains the data specific to this application are given below :package com.recyclerviewcardview; public class DataModel { String name; String version; int id_; int image; public DataModel(String name, String version, int id_, int image) { this.name = name; this.version = version; this.id_ = id_; this.image=image; } public String getName() { return name; } public String getVersion() { return version; } public int getImage() { return image; } public int getId() { return id_; } }
package com.recyclerviewcardview; public class MyData { static String[] nameArray = {"Cupcake", "Donut", "Eclair", "Froyo", "Gingerbread", "Honeycomb", "Ice Cream Sandwich","JellyBean", "Kitkat", "Lollipop", "Marshmallow"}; static String[] versionArray = {"1.5", "1.6", "2.0-2.1", "2.2-2.2.3", "2.3-2.3.7", "3.0-3.2.6", "4.0-4.0.4", "4.1-4.3.1", "4.4-4.4.4", "5.0-5.1.1","6.0-6.0.1"}; static Integer[] drawableArray = {R.drawable.cupcake, R.drawable.donut, R.drawable.eclair, R.drawable.froyo, R.drawable.gingerbread, R.drawable.honeycomb, R.drawable.ics, R.drawable.jellybean, R.drawable.kitkat, R.drawable.lollipop,R.drawable.marsh}; static Integer[] id_ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; }
Below is the output produced by our android RecyclerView and CardView example application.
As you can see the removed item is always added at the third index (fourth position in the list)
This brings an end to this tutorial about android RecyclerView and CardView.
No comments:
Post a Comment