1. Build Gradle
file : build.gradle
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.recyclerview:recyclerview:1.1.0' }
2. Menu
file : menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/action_search" android:icon="@android:drawable/ic_menu_search" android:title="@string/action_search" app:actionViewClass="androidx.appcompat.widget.SearchView" app:showAsAction="always|collapseActionView" /> </menu>
In this tutorial we will create RecyclerView in one of Tabs of TabLayout , Creating TabLayout is outside the scope of this tutorial , In the previous tutorial I have covered how to create TabLayout you can refer for it .
3. XML Layout
file : tab_one_fragment.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/fragment_bg"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
Create XML Layout file in res/layout and name it list_row.xml , This Layout defines the layout for Items of RecyclerView . Here In this example we will add two TextView inside LinearLayout .
file : list_row.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="16dp" android:background="@drawable/selector_row" android:clickable="true" android:focusableInTouchMode="true" android:focusable="true" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/country_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Name" android:textSize="20sp" /> <TextView android:id="@+id/country_iso" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="ISo" android:textSize="16sp"/> </LinearLayout>
4. Java Model
file : CountryModel.java
package com.tutorialsbuzz.recyclerview.TabFragments; public class CountryModel { String name; String isocode; CountryModel(String name, String isocode){ this.name=name; this.isocode=isocode; } public String getName() { return name; } public String getisoCode() { return isocode; } }
5. Adapter
- Create A Class RVAdapter and this class Must Extend RecyclerView.Adapter. This adapter follows the view holder design pattern, which means that you have to define a custom class that extends RecyclerView.ViewHolder (This pattern minimizes the number of calls to the costly findViewById method.) .
- Add a constructor to the custom adapter so that it has a handle to the data that the RecyclerView displays , As our data is in the form of a List<String> .
- RecyclerView.Adapter has three abstract methods that we must override .
- getItemCount() : This method return the number of items present in the data
- onCreateViewHolder() : Inside this method we specify the layout that each item of the RecyclerView should use. This is done by inflating the layout using LayoutInflater, passing the output to the constructor of the custom ViewHolder.
- onBindViewHolder() : This Method This method is very similar to the getView method of a ListView's adapter. In our example, here's where you have to set the String values to TextView.
- I have created a method setFilter , we call this method inside onQueryTextChange method of SearchView.onQueryTextListener interface by passing filtered data list and inside this method make a call to notifyDataSetChanged() api which will do the filtering magic .
file : RVAdapter.java
package com.tutorialsbuzz.recyclerview.TabFragments; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.tutorialsbuzz.recyclerview.R; import java.util.ArrayList; import java.util.List; public class RVAdapter extends RecyclerView.Adapter<ItemViewHolder> { private List<CountryModel> mCountryModel; private List<CountryModel> mOriginalCountryModel; public RVAdapter(List<CountryModel> mCountryModel) { this.mCountryModel = mCountryModel; this.mOriginalCountryModel = mCountryModel; } @Override public void onBindViewHolder(ItemViewHolder itemViewHolder, int i) { final CountryModel model = mCountryModel.get(i); itemViewHolder.bind(model); } @Override public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, viewGroup, false); return new ItemViewHolder(view); } @Override public int getItemCount() { return mCountryModel.size(); } public void setFilter(List<CountryModel> countryModels){ mCountryModel = new ArrayList<>(); mCountryModel.addAll(countryModels); notifyDataSetChanged(); } }
6. View Holder
- ItemViewHolder class and this class Must Extend RecyclerView.ViewHolder
- We already defined the XML layout list_row.xml , We are going to reuse that layout now. Inside the constructor of our custom ViewHolder, initialize the views that belong to the items of our RecyclerView.
- I have created method bind , we this method this method inside onBindViewHolder() by passing country data model class object.
package com.tutorialsbuzz.recyclerview.TabFragments; import androidx.recyclerview.widget.RecyclerView; import android.view.View; import android.widget.TextView; import com.tutorialsbuzz.recyclerview.R; public class ItemViewHolder extends RecyclerView.ViewHolder { public TextView name_TextView; public TextView iso_TextView; public ItemViewHolder(View itemView) { super(itemView); itemView.setClickable(true); name_TextView = (TextView) itemView.findViewById(R.id.country_name); iso_TextView = (TextView) itemView.findViewById(R.id.country_iso); } public void bind(CountryModel countryModel) { name_TextView.setText(countryModel.getName()); iso_TextView.setText(countryModel.getisoCode()); } }
6. Fragment
- Create a TabOneFragment which extends Fragment .
- Inside the onCreateView method get the reference to recyclerview and set the LayoutManager as LayoutLayout.
- Inside the OnActivityCreate method call to setAdpter on recyclerview instance and pass the instance of above define RVAdapter as argument.
7. Filtering Logic
- Inside the onCreateOptionMenu get the reference of searchView widget and set onQueryTextListener on it .
- Upon setting onQueryTextListener on SearchView override the onQueryTextChange and onQueryTextSubmit method.
- I have Created a method filter which takes list of CountryModel and query string as parameter , inside this method we will filter the CountryModel list on one of the constraints of CountryModel (here in this example i am filter the list on name constrain , if you want you can filter on isocode ) and return the filtered list .
- Inside the onQueryTextChange we make a call to filter method and get the return filtered list this which in-turn passed as a argument while make call to setFilter of RVAdapter .
Note : When you perform filter and then Switch between tabs in TabLayout In such scenario the recyclerview won't return the original set of data so to overcome this you have set the onActionExapndListener on MenuItem and then inside the onMenuItemActionCollapse make a call to setFilter method on adapter instance by passing the original list as argument .
file : TabOneFragment.java
package com.tutorialsbuzz.recyclerview.TabFragments; import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.core.view.MenuItemCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.appcompat.widget.SearchView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import com.tutorialsbuzz.recyclerview.R; import java.util.ArrayList; import java.util.List; import java.util.Locale; public class TabOneFragment extends Fragment implements SearchView.OnQueryTextListener { private RecyclerView recyclerview; private List<CountryModel> mCountryModel; private RVAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.tab_one_fragment, container, false); recyclerview = (RecyclerView) view.findViewById(R.id.recyclerview); LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); recyclerview.setLayoutManager(layoutManager); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setHasOptionsMenu(true); String[] locales = Locale.getISOCountries(); mCountryModel = new ArrayList<>(); for (String countryCode : locales) { Locale obj = new Locale("", countryCode); mCountryModel.add(new CountryModel(obj.getDisplayCountry(), obj.getISO3Country())); } adapter = new RVAdapter(mCountryModel); recyclerview.setAdapter(adapter); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_main, menu); final MenuItem item = menu.findItem(R.id.action_search); final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item); searchView.setOnQueryTextListener(this); item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { @Override public boolean onMenuItemActionCollapse(MenuItem item) { // Do something when collapsed adapter.setFilter(mCountryModel); return true; // Return true to collapse action view } @Override public boolean onMenuItemActionExpand(MenuItem item) { // Do something when expanded return true; // Return true to expand action view } }); } @Override public boolean onQueryTextChange(String newText) { final List<CountryModel> filteredModelList = filter(mCountryModel, newText); adapter.setFilter(filteredModelList); return true; } @Override public boolean onQueryTextSubmit(String query) { return false; } private List<CountryModel> filter(List<CountryModel> models, String query) { query = query.toLowerCase(); final List<CountryModel> filteredModelList = new ArrayList<>(); for (CountryModel model : models) { final String text = model.getName().toLowerCase(); if (text.contains(query)) { filteredModelList.add(model); } } return filteredModelList; } }
42 comments:
Good tutorials you have here am one of your fan and i really appreciate your work.
How can i add the list of country in text file/html and read it in the fragment one page. Instead of autogenerating it through ISO....
Kindly help
can you please explain how to search in normal activity without tabs
Thank you much for the tutorial and sample source code it is much appreciated! I am attempting to implement this functionality into my application. I am wondering in this app code, where does all the data come from that is displayed in the RecyclerView?
@chrisaparis
All the data is from java Locale object "Locale.getISOCountries()" , which you can see inside onViewCreated() method
Thanks a lot... :)
Hello, can you help me please? how can I get the real position from item in the search? because it is returning 0, but without the search, it return the actual position. I need open another Activity when I click on item, but I need of the position for load the data.
// after the search i get zero position onClick method, so it load wrong data
@Override
public void onClick(View v) {
int position = getAdapterPosition();
Log.i("###--->", "position " + position);
}
Sir how to access all fragment content on single mainactivity
example i've 3 fragment like 3 tab(contain editext,radiobutton like resources all type)
and 1 mainactivity
i want to access data of all fragment on sigle activity
I have implemented RecyclerView SearchView demo which is given here. Is it possible to extend this filter to two parameters? The first parameter in my example is "product name" which results in a list of companies. My App is now ready and working on one parameter. Now I need to further filter on "City name" and display the company names for a particular city. I am thinking of placing two searchviews, one to accept productname and another searchview to accept city. Can you help me to go further from here.
I have implemented RecyclerView SearchView demo which is given here. Is it possible to extend this filter to two parameters? The first parameter in my example is "product name" which results in a list of companies. My App is now ready and working on one parameter. Now I need to further filter on "City name" and display the company names for a particular city. I am thinking of placing two searchviews, one to accept productname and another searchview to accept city. Can you help me to go further from here.
Thanks a lot...
Thanks a lot. Save my time...
Great tutorial! Thank you very much.
I try to use this way to make my application in which I have a name , phone, address and IMEI and I apply the filter on its name but does not work please explain to me where the problem can be. I apologize for the bad english
I lIKE YOUR TUTORIAL
wow thanks
thank you very much for this tutorial! It was incredibly clear and helpful for me.
thank you very much for this tutorial. It was incredibly clear and helpful for me.
superb.! thanks
you need to use for loop inside your onClick. compare the string from original List with filtered List. if equal, then it is the original position
I have same problem, how to solve this?
excelente, very nice thank you... from México
Thanks a ton, your post has taught me a lot and saved my time as a developer !
You need to write the setonitemclick listener on the FILTERED method TOO (specifically, on the onQueryTextChange method). Also you need to assign the model in the filteredModelList, such as:
CountryModel countrymodel = filteredModelList.get(position);
Instead of:
CountryModel countrymodel = mCountryModel.get(position);
Otherwise, you'll always get the unfiltered position or string of an item.
hello, this is a great tutorial, but i need to add some few things and i was hoping you could help,
1) I want to add my own data to the array string instead of using the countries
2) I also want to be able to open a new activity to display the data(in your example, the countries). So anytime i click on one of the the items, it should pass the data to a new activity. Unfortunately, recyclerview does not have an OnClickActionListener.
Thank you.
[…] RecyclerView Item Filter. […]
[…] RecyclerView Item Filter. […]
[…] Android Filter RecyclerView Using SearchView In ToolBar http://www.tutorialsbuzz.com/2015/11/Android-Filter-RecyclerView-Using-SearchView-In-ToolBar.html […]
awesome tutoria.... really easy to follow and managed to implement this feature.... was able to implement getting the real position by running a custom method to go through the original listing and the search string..
[…] want to create this proyect http://tutorialsbuzz.com/2015/11/android-filter-recyclerview-using-searchview-in-toolbar.html, but the problem is I can’t add my own data to the array string instead of using the […]
Congratulations, It really was AWSOME...
from where you are accessing data
hello
in the code "setOnActionExpandListener" is deprecated how i can solve this problem?
Instead of "MenuItemCompat.setOnActionExpandListener", use "item.setOnActionExpandListener", or whatever the name of your MenuItem for action_search is
Hi Adam, it still gives me an exception java.lang.UnsupportedOperationException: This is not supported, use MenuItemCompat.setOnActionExpandListener(). please help! thanks !
how can i edit contents
looking for this from many days. Working fine. Thanks dude. many Apreciation.
this is slowing down my appplication dramatically. i can only search for one item at max, when i remove the query item and start writing next, after writing 3 letters the application hangs up. whats the reason?
you saved my life thank you <3
Where did you store your data?
i dont see a list of countries
You are my new savior. Thanks.
can this be done in xamarin.android? what is the application used this tutorial?
Post a Comment