If we need to portray complex list with bulk content with slinky animation ( i.e. material design styles) in your apps, the better choice must be the RecyclerView and CardView widgets.
In this post, we are going to understand the how to populate images in Recycler view through horizontal direction with customized CardView layout. We also learn custom ItemAnimator, onItemClickListener for RecyclerView as well. This application shows a horizontal category RecyclerView that shows the images of shirt, pant, overcoat, hat, and etc. The choices populate based on selected category from Recycler View. You can find the workflow from below video.
If you want to use a
RecyclerView
, you will need to work with the following:-
RecyclerView.Adapter
- To handle the data collection and bind it to the view -
LayoutManager
- Helps in positioning the items -
ItemAnimator
- Helps with animating the items for common operations such as Addition or Removal of an item.
Moreover, the add or remove data in Listview had been extremely difficult to do.
RecyclerView
is mandatory to implement the ViewHolder Class that was already a recommended practice in Listview but now deeply integrated with this RecyclerView framework. You can find the detailed explanation for RecyclerView components here.Why RecyclerView than ListView
-
Required ViewHolder in Adapters -
ListView
adapters do not require the use of the ViewHolder. In contrast, implementing an adapter forRecyclerView
requires the use of the ViewHolder pattern for better performance. - Customizable Item Layouts - The
RecyclerView
has aRecyclerView.LayoutManager
that allows any item layouts including horizontal lists or staggered grids. -
Easy Item Animations -
ListView
contains no special provisions through which one can animate the addition or deletion of items. In contrast, theRecyclerView
has theRecyclerView.ItemAnimator
class for handling item animations. -
Manual Data Source -
ListView
had adapters for different sources such asArrayAdapter
andCursorAdapter
for arrays and database results respectively. In contrast, theRecyclerView.Adapter
requires a custom implementation to supply the data to the adapter. -
Manual Item Decoration -
ListView
has theandroid:divider
property for easy dividers between items in the list. In contrast,RecyclerView
requires the use of aRecyclerView.ItemDecoration
object to setup much more manual divider decorations. -
Manual Click Detection -
ListView
has aAdapterView.OnItemClickListener
interface for binding to the click events for individual items in the list. In contrast,RecyclerView
only has support forRecyclerView.OnItemTouchListener
which manages individual touch events but has no built-in click handling.
Components of a RecyclerView
LayoutManager
A layout manager positions item views inside a RecyclerView
and determines when to reuse item views that are no longer visible to the user. To reuse (or recycle) a view, a layout manager may ask the adapter to replace the contents of the view with a different element from the data set. Recycling views in this manner improve performance by avoiding the creation of unnecessary views or performing expensive layout id lookups.
LinearLayoutManager -
shows items in a vertical or horizontal scrolling list.GridLayoutManager
- shows items in a grid.StaggeredGridLayoutManager -
shows items in a staggered grid.
RecyclerView.Adapter
RecyclerView
is a similar approach to the ones you already used, but with some peculiarities, such as a required ViewHolder
. You will have to override two main methods:- onCreateViewHolder() - One to inflate the view and its view holder.
- onBindViewHolder() - One to bind data to the view.
The good thing about this is that first method is called only when we really need to create a new view. No need to check if it’s being recycled.
RecyclerView.ItemAnimator
The add/delete/select operations are notified to the adapter.
DefaultItemAnimator
can be used for basic default animations and works quite well.RecyclerView.OnItemClickListener
By implementing the
RecyclerView.OnItemTouchListener
to respond to only single tap events. This is just a beginning and extended to provide more complex gestures like long click etc.Workflow for Parallel Recycler View
Now back to our Parallel Recycler View App.
Step 1 : Add recycler view dependency
compile 'com.android.support:cardview-v7:23.1.0'
compile 'com.android.support:recyclerview-v7:23.1.0'
Add these two dependencies in app.gradle
Step 2 : Add recycler view to activity_main.xml layout
<android.support.v7.widget.RecyclerView
android:id="@+id/category_recycler_view"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_below="@+id/imageUser"
android:scrollbars="none" />
Step 3 : Creating model class
public class Category implements Serializable { public String cat_name,cat_description; public int cat_id,cat_icon; }
Serializing a class file provides a fast and efficeint way to store information produced by your application.
Step 4: Creating Adapter class
The adapter's role is to convert an object to a position into a list row item to be inserted. However, with a RecyclerView the adapter requires the existence of a "ViewHolder" object which describes and provides access to all the views within each item row.
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.AKCViewHolder>{ private Context mContext; private List<Category> mCategoryList; private final static int FADE_DURATION = 300; // in milliseconds private int lastPosition = -1; public class AKCViewHolder extends RecyclerView.ViewHolder { public ImageView categoryIcon; public AKCViewHolder(View view) { super(view); categoryIcon = (ImageView) view.findViewById(R.id.categoryImage); } } public CategoryAdapter(Context mContext, List<Category> cateList) { this.mContext = mContext; this.mCategoryList = cateList; } @Override public AKCViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View categoryItem= LayoutInflater.from(parent.getContext()).inflate (R.layout.list_single_card,parent,false); return new AKCViewHolder(categoryItem); } @Override public void onBindViewHolder(AKCViewHolder holder, int position) { Category categoryItem=mCategoryList.get(position); Bitmap icon = BitmapFactory.decodeResource(mContext.getResources(),categoryItem.cat_icon); holder.categoryIcon.setImageBitmap(icon); // Set the view to scale //setScaleAnimation(holder.categoryIcon); if(CATEGORY_SELECTED_POSITION == position){ // Here I am just highlighting the background holder.categoryIcon.setBackgroundColor(mContext.getResources() .getColor(R.color.colorPickedItem)); }else{ holder.categoryIcon.setBackgroundColor(mContext.getResources() .getColor(R.color.colorItembg)); } } @Override public int getItemCount() { return mCategoryList.size(); } }
Every adapter has three primary methods:
onCreateViewHolder
to inflate the item layout and create the holder, onBindViewHolder
to set the view attributes based on the data and getItemCount
to determine the number of items.
With the adapter completed, all that is remaining is to bind the data from the adapter into the RecyclerView.
Step 5 : Adding adapter to RecyclerView
mCategoryList=new ArrayList<>(); mCategoryAdapter=new CategoryAdapter(MainActivity.this,mCategoryList); mCategoryRecyclerView = (RecyclerView) findViewById(R.id.category_recycler_view); mCategoryRecyclerView.setAdapter(mCategoryAdapter);
In MainActivity.java binding adapter to RecyclerView.
Step 6: Assigning LayoutManager to RecyclerView
// Enable optimizations if the items are static and will not change for significantly smoother scrollingmCategoryRecyclerView.setHasFixedSize(true); RecyclerView.LayoutManager mCateLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); mCategoryRecyclerView.setLayoutManager(mCateLayoutManager);
We assign the HORIZONTAL orientation at LinearLayoutManager for RecyclerView. We have to setHasFixedSize(true) by enabling optimizations if the items are static and will not change for significantly smoother scrolling.
Step 7 : Loading data to Category
private void prepareCategory(){ int[] mAccessoryIcon = new int[]{ R.drawable.category_shirt, R.drawable.category_pant, R.drawable.category_overcoat, R.drawable.category_gown, R.drawable.category_hat, R.drawable.category_tie, R.drawable.category_bride, R.drawable.category_handbag, R.drawable.category_tees, R.drawable.category_shoe, R.drawable.category_cutshoe, }; String[] mAccessoryName=getResources().getStringArray(R.array.accessoryName); for (int i=0;i<mAccessoryIcon.length;i++){ Category category=new Category(); category.cat_id=i; category.cat_name=mAccessoryName[i]; category.cat_icon=mAccessoryIcon[i]; category.cat_description=mAccessoryName[i]+" details"; mCategoryList.add(category); } mCategoryAdapter.notifyDataSetChanged(); }
Call prepareCategory() in OnCreate() to load data in mCategoryList ArrayList. Finally, compile and run the app and you should see something like the screenshot below.
Step 7: Creating custom OnItemClickListener
An important point that the guide leaves out is about handling clicks on the recycler view items. There is no such thing as
OnItemClickListener
for RecyclerViews
. Given that RecyclerView takes ListView
a step further and doesn't have a concept of a row/column, but rather
an arbitrarily laid out amount of children, they have delegated the onClick
to each one of them, or to programmer implementation. So We should implement OnItemTouchListener to achieve this issue.public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { private OnItemClickListener mListener; public interface OnItemClickListener { public void onItemClick(View view, int position); } GestureDetector mGestureDetector; public RecyclerItemClickListener(Context context, OnItemClickListener listener) { mListener = listener; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } }); } @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { View childView = view.findChildViewUnder(e.getX(), e.getY()); if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { mListener.onItemClick(childView, view.getChildAdapterPosition(childView)); } return false; } @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } }
Step 8: Implementing addOnItemTouchListener
mCategoryRecyclerView.addOnItemTouchListener( new RecyclerItemClickListener(MainActivity.this, new RecyclerItemClickListener.
OnItemClickListener() { @Override public void onItemClick(View view, int position) { // Updating old as well as new positions
mCategoryAdapter.notifyItemChanged(CATEGORY_SELECTED_POSITION); CATEGORY_SELECTED_POSITION = position; mCategoryAdapter.notifyItemChanged(CATEGORY_SELECTED_POSITION); Category category=mCategoryList.get(position); Toast.makeText(view.getContext(),"Category : "+
category.cat_name,Toast.LENGTH_SHORT).show(); // Load date in choice recyclerview
pickChoice(position); } }));
By adding addOnItemTouchListener(), we can implement onItemClick in RecyclerView.
I have uploaded the full source code in GitHub,
Happy coding,
Cheers!!!
No comments:
Post a Comment