Once you have added a RecyclerView widget to your layout, obtain a handle to the object, connect it to a layout manager and attach an adapter for the data to be displayed:
mRecyclerView =(RecyclerView)findViewById(R.id.my_recycler_view);// set a layout manager (LinearLayoutManager in this example)
mLayoutManager =newLinearLayoutManager(getApplicationContext());
mRecyclerView.setLayoutManager(mLayoutManager);// specify an adapter
mAdapter =newMyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
Or simply setup layout manager from xml by adding this lines:
If you know that changes in content of the RecyclerView won't change the layout size of the RecyclerView, use the following code to improve the performance of the component. If RecyclerView has a fixed size, it knows that RecyclerView itself will not resize due to its children, so it doesn’t call request layout at all. It just handles the change itself. If invalidating whatever the parent is, the coordinator, layout, or whatever. (you can use this method even before setting LayoutManager and Adapter):
mRecyclerView.setHasFixedSize(true);
RecyclerView provides these built-in layout managers to use. So you can create a list, a grid and a staggered grid using RecyclerView:
[LinearLayoutManager](https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager.html) shows items in a vertical or horizontal
scrolling list.
1. [GridLayoutManager](https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html) shows items in a grid.
1. [StaggeredGridLayoutManager](https://developer.android.com/reference/android/support/v7/widget/StaggeredGridLayoutManager.html) shows items in a staggered grid.
Smoother loading of items
If the items in your RecyclerView load data from the network (commonly images) or carry out other processing, that can take a significant amount of time and you may end up with items on-screen but not fully loaded. To avoid this you can extend the existing LinearLayoutManager to preload a number of items before they become visible on-screen:
packagecom.example;importandroid.content.Context;importandroid.support.v7.widget.LinearLayoutManager;importandroid.support.v7.widget.OrientationHelper;importandroid.support.v7.widget.RecyclerView;/**
* A LinearLayoutManager that preloads items off-screen.
* <p>
* Preloading is useful in situations where items might take some time to load
* fully, commonly because they have maps, images or other items that require
* network requests to complete before they can be displayed.
* <p>
* By default, this layout will load a single additional page's worth of items,
* a page being a pixel measure equivalent to the on-screen size of the
* recycler view. This can be altered using the relevant constructor, or
* through the {@link #setPages(int)} method.
*/publicclassPreLoadingLinearLayoutManagerextendsLinearLayoutManager{privateint mPages =1;privateOrientationHelper mOrientationHelper;publicPreLoadingLinearLayoutManager(finalContext context){super(context);}publicPreLoadingLinearLayoutManager(finalContext context,finalint pages){super(context);this.mPages = pages;}publicPreLoadingLinearLayoutManager(finalContext context,finalint orientation,finalboolean reverseLayout){super(context, orientation, reverseLayout);}@OverridepublicvoidsetOrientation(finalint orientation){super.setOrientation(orientation);
mOrientationHelper =null;}/**
* Set the number of pages of layout that will be preloaded off-screen,
* a page being a pixel measure equivalent to the on-screen size of the
* recycler view.
* @param pages the number of pages; can be {@code 0} to disable preloading
*/publicvoidsetPages(finalint pages){this.mPages = pages;}@OverrideprotectedintgetExtraLayoutSpace(finalRecyclerView.State state){if(mOrientationHelper ==null){
mOrientationHelper =OrientationHelper.createOrientationHelper(this,getOrientation());}return mOrientationHelper.getTotalSpace()* mPages;}}
Animate data change
RecyclerView will perform a relevant animation if any of the "notify" methods are used except for notifyDataSetChanged; this includes notifyItemChanged, notifyItemInserted, notifyItemMoved, notifyItemRemoved, etc.
The adapter should extend this class instead of RecyclerView.Adapter.
importandroid.support.annotation.NonNull;importandroid.support.v7.widget.RecyclerView;importjava.util.List;publicabstractclassAnimatedRecyclerAdapter<T, VH extendsRecyclerView.ViewHolder>extendsRecyclerView.Adapter<VH>{protectedList<T> models;protectedAnimatedRecyclerAdapter(@NonNullList<T> models){this.models = models;}//Set new models.publicvoidsetModels(@NonNullfinalList<T> models){applyAndAnimateRemovals(models);applyAndAnimateAdditions(models);applyAndAnimateMovedItems(models);}//Remove an item at position and notify changes.privateTremoveItem(int position){finalT model = models.remove(position);notifyItemRemoved(position);return model;}//Add an item at position and notify changes.privatevoidaddItem(int position,T model){
models.add(position, model);notifyItemInserted(position);}//Move an item at fromPosition to toPosition and notify changes.privatevoidmoveItem(int fromPosition,int toPosition){finalT model = models.remove(fromPosition);
models.add(toPosition, model);notifyItemMoved(fromPosition, toPosition);}//Remove items that no longer exist in the new models.privatevoidapplyAndAnimateRemovals(@NonNullfinalList<T> newTs){for(int i = models.size()-1; i >=0; i--){finalT model = models.get(i);if(!newTs.contains(model)){removeItem(i);}}}//Add items that do not exist in the old models.privatevoidapplyAndAnimateAdditions(@NonNullfinalList<T> newTs){for(int i =0, count = newTs.size(); i < count; i++){finalT model = newTs.get(i);if(!models.contains(model)){addItem(i, model);}}}//Move items that have changed their position.privatevoidapplyAndAnimateMovedItems(@NonNullfinalList<T> newTs){for(int toPosition = newTs.size()-1; toPosition >=0; toPosition--){finalT model = newTs.get(toPosition);finalint fromPosition = models.indexOf(model);if(fromPosition >=0&& fromPosition != toPosition){moveItem(fromPosition, toPosition);}}}}
You should NOT use the same List for setModels and List in the adapter.
You declare models as global variables. DataModel is a dummy class only.
Initialize models before pass it to adapter. YourAdapter is the implementation of AnimatedRecyclerAdapter.
models =newArrayList<>();//Add models
models.add(newDataModel());//Do NOT pass the models directly. Otherwise, when you modify global models, //you will also modify models in adapter.//adapter = new YourAdapter(models); <- This is wrong.
adapter =newYourAdapter(newArrayList(models));
Call this after you have updated your global models.
adapter.setModels(newArrayList(models));
If you do not override equals, all the comparison is compared by reference.
Example using SortedList
Android introduced the SortedList(opens new window) class soon after RecyclerView was introduced. This class handles all 'notify' method calls to the RecyclerView.Adapter to ensure proper animation, and even allows batching multiple changes, so the animations don't jitter.
importandroid.support.v7.util.SortedList;importandroid.support.v7.widget.RecyclerView;importandroid.support.v7.widget.util.SortedListAdapterCallback;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importjava.util.List;publicclassMyAdapterextendsRecyclerView.Adapter<MyAdapter.ViewHolder>{privateSortedList<DataModel> mSortedList;classViewHolderextendsRecyclerView.ViewHolder{TextView text;CheckBox checkBox;ViewHolder(View itemView){super(itemView);//Initiate your code here...}voidsetDataModel(DataModel model){//Update your UI with the data model passed here...
text.setText(modle.getText());
checkBox.setChecked(model.isChecked());}}publicMyAdapter(){
mSortedList =newSortedList<>(DataModel.class,newSortedListAdapterCallback<DataModel>(this){@Overridepublicintcompare(DataModel o1,DataModel o2){//This gets called to find the ordering between objects in the array.if(o1.someValue()< o2.someValue()){return-1;}elseif(o1.someValue()> o2.someValue()){return1;}else{return0;}}@OverridepublicbooleanareContentsTheSame(DataModel oldItem,DataModel newItem){//This is to see of the content of this object has changed. These items are only considered equal if areItemsTheSame() returned true.//If this returns false, onBindViewHolder() is called with the holder containing the item, and the item's position.return oldItem.getText().equals(newItem.getText())&& oldItem.isChecked()== newItem.isChecked();}@OverridepublicbooleanareItemsTheSame(DataModel item1,DataModel item2){//Checks to see if these two items are the same. If not, it is added to the list, otherwise, check if content has changed.return item1.equals(item2);}});}@OverridepublicViewHolderonCreateViewHolder(ViewGroup parent,int viewType){View itemView =//Initiate your item view here.returnnewViewHolder(itemView);}@OverridepublicvoidonBindViewHolder(ViewHolder holder,int position){//Just update the holder with the object in the sorted list from the given positionDataModel model = mSortedList.get(position);if(model !=null){
holder.setDataModel(model);}}@OverridepublicintgetItemCount(){return mSortedList.size();}publicvoidresetList(List<DataModel> models){//If you are performing multiple changes, use the batching methods to ensure proper animation.
mSortedList.beginBatchedUpdates();
mSortedList.clear();
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();}//The following methods each modify the data set and automatically handles calling the appropriate 'notify' method on the adapter.publicvoidaddModel(DataModel model){
mSortedList.add(model);}publicvoidaddModels(List<DataModel> models){
mSortedList.addAll(models);}publicvoidclear(){
mSortedList.clear();}publicvoidremoveModel(DataModel model){
mSortedList.remove(model);}publicvoidremoveModelAt(int i){
mSortedList.removeItemAt(i);}}
By default, Android Data Binding library generates a ViewDataBinding class based on the layout file name, converting it to Pascal case and suffixing "Binding" to it. For this example it would be MyItemBinding for the layout file my_item.xml. That Binding class would also have a setter method to set the object defined as data in the layout file(ItemModel for this example).
Now that we have all the pieces we can implement our adapter like this:
Sometimes a RecyclerView will need to use several types of Views to be displayed in the list shown in the UI, and each View needs a different layout xml to be inflated.
For this issue, you may use different ViewHolders in single Adapter, by using a special method in RecyclerView - getItemViewType(int position).
Below is example of using two ViewHolders:
A ViewHolder for displaying list entries
A ViewHolder for displaying multiple header views
@OverridepublicRecyclerView.ViewHolderonCreateViewHolder(ViewGroup parent,int viewType){View itemView =LayoutInflater.from(context).inflate(viewType, parent,false);returnViewHolder.create(itemView, viewType);}@OverridepublicvoidonBindViewHolder(RecyclerView.ViewHolder holder,int position){finalItem model =this.items.get(position);((ViewHolder) holder).bind(model);}@OverridepublicintgetItemViewType(int position){return inSearchState ?R.layout.item_header :R.layout.item_entry;}abstractclassViewHolder{abstractvoidbind(Item model);publicstaticViewHoldercreate(View v,int viewType){return viewType ==R.layout.item_header ?newHeaderViewHolder(v):newEntryViewHolder(v);}}staticclassEntryViewHolderextendsViewHolder{privateView v;publicEntryViewHolder(View v){this.v = v;}@Overridepublicvoidbind(Item model){// Bind item data to entry view.}}staticclassHeaderViewHolderextendsViewHolder{privateView v;publicHeaderViewHolder(View v){this.v = v;}@Overridepublicvoidbind(Item model){// Bind item data to header view.}}
Filter items inside RecyclerView with a SearchView
add filter method in RecyclerView.Adapter:
publicvoidfilter(String text){if(text.isEmpty()){
items.clear();
items.addAll(itemsCopy);}else{ArrayList<PhoneBookItem> result =newArrayList<>();
text = text.toLowerCase();for(PhoneBookItem item: itemsCopy){//match by name or phoneif(item.name.toLowerCase().contains(text)|| item.phone.toLowerCase().contains(text)){
result.add(item);}}
items.clear();
items.addAll(result);}notifyDataSetChanged();}
itemsCopy is initialized in adapter's constructor like itemsCopy.addAll(items).
If you do so, just call filter from OnQueryTextListener from SearchView:
You can implement the swipe-to-dismiss and drag-and-drop features with the RecyclerView without using 3rd party libraries.
Just use the ItemTouchHelper(opens new window) class included in the RecyclerView support library.
Instantiate the ItemTouchHelper with the SimpleCallback(opens new window) callback and depending on which functionality you support, you should override onMove(RecyclerView, ViewHolder, ViewHolder) and / or onSwiped(ViewHolder, int)and and finally attach to your RecyclerView.
ItemTouchHelper.SimpleCallback simpleItemTouchCallback =newItemTouchHelper.SimpleCallback(0,ItemTouchHelper.LEFT |ItemTouchHelper.RIGHT){@OverridepublicvoidonSwiped(RecyclerView.ViewHolder viewHolder,int swipeDir){// remove item from adapter}@OverridepublicbooleanonMove(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder,RecyclerView.ViewHolder target){finalint fromPos = viewHolder.getAdapterPosition();finalint toPos = target.getAdapterPosition();// move item in `fromPos` to `toPos` in adapter.returntrue;// true if moved, false otherwise}};ItemTouchHelper itemTouchHelper =newItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
It's worth mentioning that SimpleCallback constructor applies the same swiping strategy to all items in the RecyclerView. It's possible in any case to update the default swiping direction for specific items by simply overriding method getSwipeDirs(RecyclerView, ViewHolder).
Let's suppose for example that our RecyclerView includes a HeaderViewHolder and that we obviously don't want to apply swiping to it. It will be enough to override getSwipeDirs as follows:
@OverridepublicintgetSwipeDirs(RecyclerView recyclerView,RecyclerView.ViewHolder viewHolder){if(viewHolder instanceofHeaderViewHolder){// no swipe for headerreturn0;}// default swipe for all other itemsreturnsuper.getSwipeDirs(recyclerView, viewHolder);}
Add header/footer to a RecyclerView
This is a sample adapter code.
publicclassSampleAdapterextendsRecyclerView.Adapter<RecyclerView.ViewHolder>{privatestaticfinalint FOOTER_VIEW =1;// Define a view holder for Footer viewpublicclassFooterViewHolderextendsViewHolder{publicFooterViewHolder(View itemView){super(itemView);
itemView.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View v){// Do whatever you want on clicking the item}});}}// Now define the viewholder for Normal list itempublicclassNormalViewHolderextendsViewHolder{publicNormalViewHolder(View itemView){super(itemView);
itemView.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(View v){// Do whatever you want on clicking the normal items }});}}// And now in onCreateViewHolder you have to pass the correct view// while populating the list item.@OverridepublicRecyclerView.ViewHolderonCreateViewHolder(ViewGroup parent,int viewType){View v;if(viewType == FOOTER_VIEW){
v =LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_footer, parent,false);FooterViewHolder vh =newFooterViewHolder(v);return vh;}
v =LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_normal, parent,false);NormalViewHolder vh =newNormalViewHolder(v);return vh;}// Now bind the viewholders in onBindViewHolder@OverridepublicvoidonBindViewHolder(RecyclerView.ViewHolder holder,int position){try{if(holder instanceofNormalViewHolder){NormalViewHolder vh =(NormalViewHolder) holder;
vh.bindView(position);}elseif(holder instanceofFooterViewHolder){FooterViewHolder vh =(FooterViewHolder) holder;}}catch(Exception e){
e.printStackTrace();}}// Now the critical part. You have return the exact item count of your list// I've only one footer. So I returned data.size() + 1// If you've multiple headers and footers, you've to return total count// like, headers.size() + data.size() + footers.size()@OverridepublicintgetItemCount(){if(data ==null){return0;}if(data.size()==0){//Return 1 here to show nothingreturn1;}// Add extra view to show the footer viewreturn data.size()+1;}// Now define getItemViewType of your own. @OverridepublicintgetItemViewType(int position){if(position == data.size()){// This is where we'll add footer.return FOOTER_VIEW;}returnsuper.getItemViewType(position);}// So you're done with adding a footer and its action on onClick. // Now set the default ViewHolder for NormalViewHolderpublicclassViewHolderextendsRecyclerView.ViewHolder{// Define elements of a row herepublicViewHolder(View itemView){super(itemView);// Find view by ID and initialize here}publicvoidbindView(int position){// bindView() method to implement actions}}}
While the above answer will work you can use this approach as well using a recycler view using a NestedScrollView .You can add a layout for header using the following approach:
Step 3:
Now every backend logic is complete now it's time to execute this logic.It's simple you can override load method where you create object of your adapter.this method is automatically call while user reach at end of the listing.
adapter = new ViewAllCategoryAdapter(CONTEXT, YOURLIST) {
@Override
public void load() {
/* do your stuff here */
/* This method is automatically call while user reach at end of your list. */
}
};
recycleCategory.setAdapter(adapter);
Now load() method automatically call while user scroll at end of list.
Add an adapter and call .notifyDataSetChanged(); as usual !
This is not an inbuilt feature of Recyclerview but added in the support libraries. So don't forget to include this in your app level build.gradle file
// Get drawable object
Drawable mDivider = ContextCompat.getDrawable(m_jContext, R.drawable.divider);
// Create a DividerItemDecoration whose orientation is Horizontal
DividerItemDecoration hItemDecoration = new DividerItemDecoration(m_jContext,
DividerItemDecoration.HORIZONTAL);
// Set the drawable on it
hItemDecoration.setDrawable(mDivider);
// Create a DividerItemDecoration whose orientation is vertical
DividerItemDecoration vItemDecoration = new DividerItemDecoration(m_jContext,
DividerItemDecoration.VERTICAL);
// Set the drawable on it
vItemDecoration.setDrawable(mDivider);
A subclass of RecyclerView.Adapter responsible for providing views that represent items in a data set
Position
The position of a data item within an Adapter
Index
The index of an attached child view as used in a call to getChildAt(int). Contrast with Position
Binding
The process of preparing a child view to display data corresponding to a position within the adapter
Recycle (view)
A view previously used to display data for a specific adapter position may be placed in a cache for later reuse to display the same type of data again later. This can drastically improve performance by skipping initial layout inflation or construction
Scrap (view)
A child view that has entered into a temporarily detached state during layout. Scrap views may be reused without becoming fully detached from the parent RecyclerView, either unmodified if no rebinding is required or modified by the adapter if the view was considered dirty
Dirty (view)
A child view that must be rebound by the adapter before being displayed
Remarks
The RecyclerView is a flexible view for providing a limited window into a large data set.
Before using the RecyclerView you have to add the support library dependency in the build.gradle file:
dependencies {// Match the version of your support library dependency
compile 'com.android.support:recyclerview-v7:25.3.1'}
You can find latest version number of recyclerview from official site(opens new window).
Other related topics:
There are other topics which describe the RecyclerView components: