In this example, we’ll see how to search filter an android listview.

We’ll use a SearchView component.

GRADLE FILES

We’ll edit the app level build.gadle adding some dependencies.

build.gradle

  • Our ListView will comprise cardviews so we add cardview dependency.
    apply plugin: 'com.android.application'

    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"

        defaultConfig {
            applicationId "com.tutorials.hp.lvfilter"
            minSdkVersion 15
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:23.2.1'
        compile 'com.android.support:design:23.2.1'
        compile 'com.android.support:cardview-v7:23.2.1'
    }

LAYOUTS

We’ll have these three layouts in our project:

1. activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout 
        
        
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_fitsSystemWindows="true"
        tools_context="com.tutorials.hp.lvfilter.MainActivity">

        <android.support.design.widget.AppBarLayout
            android_layout_width="match_parent"
            android_layout_height="wrap_content"
            android_theme="@style/AppTheme.AppBarOverlay">

            <android.support.v7.widget.Toolbar
                android_id="@+id/toolbar"
                android_layout_width="match_parent"
                android_layout_height="?attr/actionBarSize"
                android_background="?attr/colorPrimary"
                app_popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.AppBarLayout>

        <include layout="@layout/content_main" />

        <android.support.design.widget.FloatingActionButton
            android_id="@+id/fab"
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_layout_gravity="bottom|end"
            android_layout_margin="@dimen/fab_margin"
            android_src="@android:drawable/ic_dialog_email" />

    </android.support.design.widget.CoordinatorLayout>

2. content_main.xml

  • This layout will hold our ListView and SearchView.
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout 
        
        
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_paddingBottom="@dimen/activity_vertical_margin"
        android_paddingLeft="@dimen/activity_horizontal_margin"
        android_paddingRight="@dimen/activity_horizontal_margin"
        android_paddingTop="@dimen/activity_vertical_margin"
        app_layout_behavior="@string/appbar_scrolling_view_behavior"
        tools_context="com.tutorials.hp.lvfilter.MainActivity"
        tools_showIn="@layout/activity_main">

        <android.support.v7.widget.SearchView
            android_id="@+id/mSearch"
            android_layout_width="match_parent"
            android_layout_height="50dp"

            app_defaultQueryHint="Search.."

            />
        <ListView
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_id="@+id/lv"
            android_layout_below="@+id/mSearch"
            android_layout_alignParentLeft="true"
            android_layout_alignParentStart="true" />
    </RelativeLayout>

3. model.xml

  • This layout will define the model for our custom rows.
  • Our ListView will have images and text.
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.CardView 
        android_orientation="horizontal" android_layout_width="match_parent"
        
        android_layout_margin="10dp"
        card_view_cardCornerRadius="10dp"
        card_view_cardElevation="10dp"

        android_layout_height="wrap_content">

        <RelativeLayout
            android_layout_width="match_parent"
            android_layout_height="match_parent">

            <ImageView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_id="@+id/movieImage"
                android_padding="10dp"
                android_src="@drawable/ghost" />

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceLarge"
                android_text="Name"
                android_id="@+id/nameTxt"
                android_padding="10dp"
                android_textColor="@color/colorAccent"
                android_layout_below="@+id/movieImage"
                android_layout_alignParentLeft="true"
                 />

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceLarge"
                android_text=" John Doe a former FBI Agent and now Physics teacher .is wrongly accussed of murdering an innocent child.He makes it his business to find the bad guys who did taht.He convinces hacker Aram to join him.....
                "
                android_id="@+id/descTxt"
                android_padding="10dp"
                android_layout_below="@+id/nameTxt"
                android_layout_alignParentLeft="true"
                />

            <TextView
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_textAppearance="?android:attr/textAppearanceMedium"
                android_text="TV Show"
                android_id="@+id/posTxt"
                android_padding="10dp"

                android_layout_below="@+id/movieImage"
                android_layout_alignParentRight="true" />

            <CheckBox
                android_layout_width="wrap_content"
                android_layout_height="wrap_content"
                android_id="@+id/chk"
                android_layout_alignParentRight="true"
                />

        </RelativeLayout>
    </android.support.v7.widget.CardView>

JAVA CLASSES

Here are our Java classes:

1. Movie.java

  • Our data object.
  • Will represent a single movies.
    package com.tutorials.hp.lvfilter;

    public class Movie {

        private String name;
        private int image;

        public Movie(String name, int image) {
            this.name = name;
            this.image = image;
        }

        public String getName() {
            return name;
        }

        public int getImage() {
            return image;
        }
    }

2. ItemClickListner

  • An interface.
  • Defines the signature for our OnItemClick() method.
    package com.tutorials.hp.lvfilter;

    import android.view.View;

    public interface ItemClickListener {

        void onItemClick(View v);
    }

3. MyViewHolder.java

  • View holder class.
    package com.tutorials.hp.lvfilter;

    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;

    public class MyViewHolder implements View.OnClickListener {

        ImageView img;
        TextView nameTxt;
        ItemClickListener itemClickListener;

        public MyViewHolder(View v) {
            img= (ImageView) v.findViewById(R.id.movieImage);
            nameTxt= (TextView) v.findViewById(R.id.nameTxt);

            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            this.itemClickListener.onItemClick(v);
        }

        public void setItemClickListener(ItemClickListener ic)
        {
            this.itemClickListener=ic;
        }
    }

4. MyAdapter.java

  • Our adapter class.
  • Derives from BaseAdapter.
  • Implements Filterable.
    package com.tutorials.hp.lvfilter;

    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.Filter;
    import android.widget.Filterable;
    import android.widget.Toast;

    import java.util.ArrayList;

    public class MyAdapter extends BaseAdapter implements Filterable {

        Context c;
        ArrayList<Movie> movies;
        LayoutInflater inflater;

        ArrayList<Movie> filterList;
        CustomFilter filter;

        public MyAdapter(Context c, ArrayList<Movie> movies) {
            this.c = c;
            this.movies = movies;
            this.filterList=movies;
        }

        //TOTLA NUM OF MOVIES
        @Override
        public int getCount() {
            return movies.size();
        }

        //GET A SINGLE MOVIE
        @Override
        public Object getItem(int position) {
            return movies.get(position);
        }

        //IDENTITDIER
        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {

            if(inflater==null)
            {
                inflater= (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            }

            //PERFORM INFLATION
            if(convertView==null)
            {
                convertView=inflater.inflate(R.layout.model,null);
            }

            //BIND DATA TO VIEWS
            MyViewHolder holder=new MyViewHolder(convertView);
            holder.nameTxt.setText(movies.get(position).getName());
            holder.img.setImageResource(movies.get(position).getImage());

            holder.setItemClickListener(new ItemClickListener() {
                @Override
                public void onItemClick(View v) {
                    Toast.makeText(c,movies.get(position).getName(),Toast.LENGTH_SHORT).show();
                }
            });

            //RETURN A ROW
            return convertView;
        }

        @Override
        public Filter getFilter() {

            if(filter==null)
            {
                filter=new CustomFilter(filterList,this);
            }

            return filter;
        }
    }

5. CustomFilter.java

  • This class is responsible for our custom filtering.
  • Derives from android.widget.Filter.
    package com.tutorials.hp.lvfilter;

    import android.widget.Filter;

    import java.util.ArrayList;

    public class CustomFilter extends Filter {

        ArrayList<Movie> filterList;
        MyAdapter adapter;

        public CustomFilter(ArrayList<Movie> filterList, MyAdapter adapter) {
            this.filterList = filterList;
            this.adapter = adapter;
        }

        //FILTERING
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

            //RESULTS
            FilterResults results=new FilterResults();

            //VALIDATION
            if(constraint != null && constraint.length()>0)
            {

                //CHANGE TO UPPER FOR CONSISTENCY
                constraint=constraint.toString().toUpperCase();

                ArrayList<Movie> filteredMovies=new ArrayList<>();

                //LOOP THRU FILTER LIST
                for(int i=0;i<filterList.size();i++)
                {
                    //FILTER
                    if(filterList.get(i).getName().toUpperCase().contains(constraint))
                    {
                        filteredMovies.add(filterList.get(i));
                    }
                }

                results.count=filteredMovies.size();
                results.values=filteredMovies;
            }else
            {
                results.count=filterList.size();
               results.values=filterList;
            }

            return results;
        }

        //PUBLISH RESULTS

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {

            adapter.movies= (ArrayList<Movie>) results.values;
            adapter.notifyDataSetChanged();

        }
    }

6. MainActivity.java

  • Our launcher activity.
  • References both our ListView and SearchView.
  • Then sets the adapter to ListView.
  • Listens to OnQueryTextChange events on the searchview.