In this tutorial, we will learn how can we filter the recyclerview item by using the Search view in toolbar or action bar? Recyclerview is the major used component in building the android application. And if the data is very huge then we can not find the specific item by scroll. So we need to filter by name while entering the text on search view. SearchView is an awesome component that provides the search with animated expand and collapse action.
Here is the recommended video which I have implemented search view in this app. Please check this video for better understanding.
Let’s integrate this feature in the sample project. Very first thing we need to add relevant dependencies in your build.gradle file.
compile 'com.android.support:recyclerview-v7:26.0.1' compile 'com.android.support:cardview-v7:26.0.1' compile 'com.android.support:design:26.0.1'
Now I need to create the menu_main.xml of item search inside the res/menu folder.
<?xml version="1.0" encoding="utf-8"?> <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:title="@string/app_name" app:actionViewClass="android.support.v7.widget.SearchView" android:icon="@android:drawable/ic_menu_search" app:showAsAction="always|collapseActionView" /> </menu>
Let’s load the data on recyclerview from a database. I am not going into the deep to load the data from the database. here I suppose that I have fetched the data of the table and loaded into List. As everyone knows that we need to bind the recyclerview item by an adapter. Let’s create the adapter and resource layout to inflate the data on view.
<?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:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.CardView app:cardCornerRadius="0dp" android:layout_margin="3dp" app:cardUseCompatPadding="true" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:padding="8dp" android:id="@+id/relative" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:src="@drawable/movie_icon" android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="200dp" /> <RelativeLayout android:id="@+id/info" android:padding="5dp" android:layout_below="@+id/imageView" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/name" android:textSize="15sp" android:textStyle="bold" android:text="@string/app_name" android:ellipsize="end" android:singleLine="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:textSize="13sp" android:id="@+id/releasyear" android:text="@string/app_name" android:layout_below="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:layout_below="@+id/releasyear" android:id="@+id/star" android:src="@drawable/ic_stars_yellow_900_24dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/rating" android:layout_below="@+id/releasyear" android:layout_toRightOf="@+id/star" android:layout_centerVertical="true" android:layout_marginTop="3dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout> </RelativeLayout> </android.support.v7.widget.CardView> </RelativeLayout>
Let’s use this layout for my adapter.
public class ImDbAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<IMBD> itemModels; private Context context; private onItemClickListener listener; public ImDbAdapter(Context context, List<IMBD> imbdList, Fragment fragment) { this.itemModels = imbdList; this.context = context; this.listener = (onItemClickListener) fragment; } @Override public int getItemCount() { return itemModels.size(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_layout, viewGroup, false); return new ItemViewHolder(itemView); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { IMBD model = itemModels.get(position); initializeViews(model, holder, position); } private void initializeViews(final IMBD model, final RecyclerView.ViewHolder holder, final int position) { ((ItemViewHolder)holder).name.setText(model.getName()); ((ItemViewHolder)holder).releasyear.setText("Release Year: "+model.getYearofrelease()); ((ItemViewHolder)holder).rating.setText(""+model.getRating()); ((ItemViewHolder)holder).relative.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { listener.itemDetailClick(model); } }); String imageUrl = model.getImageurl(); if (imageUrl != null && !imageUrl.isEmpty()){ Picasso.with(context) .load(imageUrl) .placeholder(R.drawable.movie_icon) .error(R.drawable.movie_icon) .into(((ItemViewHolder)holder).imageView); } } public static class ItemViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.name) TextView name; @BindView(R.id.releasyear) TextView releasyear; @BindView(R.id.rating) TextView rating; @BindView(R.id.imageView) ImageView imageView; @BindView(R.id.relative) RelativeLayout relative; public ItemViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } public interface onItemClickListener{ public void itemDetailClick(IMBD imbd); } public void setSearchResult(List<IMBD> result) { itemModels = result; notifyDataSetChanged(); } }
Here I am using the fragment So we need to enable the menu option in onCreate() of Fragment and override the onCreateOptionMenu() to allow searches to filter the recycled view data by using SearchView.
I used MVP design pattern with Dagger2 dependency injection in this sample project. If you want to get the detail of MVP design pattern in Java then Please check this post MVP architectural design pattern with RxJava. Here is the detail about the Dagger2 Dependency Injection.
public class ImdbListFragment extends Fragment implements ImdbListContract.View, ImDbAdapter.onItemClickListener, SearchView.OnQueryTextListener{ @BindView(R.id.recyclerView) RecyclerView recyclerView; @Inject ImdbListContract.Presenter mPresenter; private ImDbAdapter mImDbAdapter; private List<IMBD> mListImDb; public static ImdbListFragment newInstance() { return new ImdbListFragment(); } @Override public void onResume() { super.onResume(); mPresenter.subscribe(); } @Override public void onPause() { super.onPause(); mPresenter.unSubscribe(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // do things if you want to create only first time when activity created. } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); injectDependency(); mPresenter.attachView(this); setHasOptionsMenu(true); } private void injectDependency() { ApplicationComponent applicationComponent = ((MainApplication) getActivity().getApplication()).getApplicationComponent(); ImdbListComponent imdbListComponent = DaggerImdbListComponent.builder() .applicationComponent(applicationComponent) .imdbListModule(new ImdbListModule()) .build(); imdbListComponent.inject(this); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_imdb_list, container, false); ButterKnife.bind(this, root); if (mPresenter != null) { if (mPresenter.getCountDb() > 0) { mPresenter.loadImDbDb(); } else { Log.v("", "Error in loading."); } } return root; } @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 onMenuItemActionExpand(MenuItem item) { return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { // Do something when collapsed mImDbAdapter.setSearchResult(mListImDb); return true; // Return true to collapse action view } }); } @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { final List<IMBD> filteredModelList = filter(mListImDb, newText); mImDbAdapter.setSearchResult(filteredModelList); return true; } private List<IMBD> filter(List<IMBD> models, String query) { query = query.toLowerCase(); final List<IMBD> filteredModelList = new ArrayList<>(); for (IMBD model : models) { final String text = model.getName().toLowerCase(); if (text.contains(query)) { filteredModelList.add(model); } } return filteredModelList; } @Override public void onImDbOk(List<IMBD> imbdList) { mListImDb = imbdList; mImDbAdapter = new ImDbAdapter(getActivity(), imbdList, this); recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2)); recyclerView.setAdapter(mImDbAdapter); } @Override public void showLoadErrorMessage(String errorMsg) { Toast.makeText(getActivity(), errorMsg, Toast.LENGTH_LONG).show(); } @Override public void showEmptyView(boolean isShow) { // show error view if any } @Override public void itemDetailClick(IMBD imbd) { String imbdDetailLink = imbd.getDetailLink(); } }
Wrapping Up: This is the great implementation of RecylerView item filter by using the SearchView in ToolBar. Let’s use this feature in your app to make your application more awesome and powerful.
Here is the Github link for full source code.
Please do subscribe your email to get the every newsletter from this blog and if you feel that this post helps you then do not forget to share and comment below.
You can learn all articles of MobologicPlus from the android app, which is available to download below.
[appbox googleplay mobi.androapp.mobologicplus.c7929]
Happy Coding 🙂
I am a very enthusiastic Android developer to build solid Android apps. I have a keen interest in developing for Android and have published apps to the Google Play Store. I always open to learning new technologies. For any help drop us a line anytime at contact@mobologicplus.com
Great tutorial sunil… Can you please guide on how to filter search view if there are two or more lists all placed in different activities….
thank you sir
Thank you for sharing such good information.