Android Filter Recyclerview by using SearchView in ToolBar or actionbar

Sharing is caring!

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 🙂

5 2 votes
Article Rating
Android Filter Recyclerview by using SearchView in ToolBar or actionbar
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Amit jain

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….

hasan

thank you sir

Anmol

Thank you for sharing such good information.

Scroll to top
3
0
Would love your thoughts, please comment.x
()
x