[android] Custom Listview Adapter with filter Android

Please am trying to implement a filter on my listview. But whenever the text change, the list disappears.Please Help Here are my codes. The adapter class.

package com.talagbe.schymn;

import java.util.ArrayList;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class HymnsAdapter extends ArrayAdapter<Hymns> {
ArrayList<Hymns> hymnarray;
Context context;
LayoutInflater inflater;
int Resource;


public HymnsAdapter(Context context, int resource, ArrayList<Hymns> objects) {
    super(context, resource, objects);
    // TODO Auto-generated constructor stub

    hymnarray=objects;
    Resource= resource;
    this.context=context;
    inflater= (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
     ViewHolder holder;
     if(convertView==null){

         convertView= inflater.inflate(Resource,null);
         holder= new ViewHolder();
         holder.hymntitle= (TextView) convertView.findViewById(R.id.Hymn_title);
        // holder.hymntext= (TextView) convertView.findViewById(R.id.Channel_name);


         convertView.setTag(holder);

     }else{
         holder=(ViewHolder)convertView.getTag();
     }

     holder.hymntitle.setText(hymnarray.get(position).getTitle());
     //holder.hymntext.setText(hymnarray.get(position).getText());

    return convertView;


}


   static class ViewHolder{

    public TextView hymntitle;
    public TextView hymntext;

}

 }

Here is the other class where am trying to implement the filter. I have an edittext,where i implement on textChangeListener

package com.talagbe.schymn;

import java.util.ArrayList;

import database.DatabaseHelper;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.widget.AdapterView.OnItemClickListener;

 public class Home extends Fragment {

    private static final String DB_NAME = "schymn.sqlite";
    private static final String TABLE_NAME = "Hymns";
    private static final String Hymn_ID = "_id";
    private static final String Hymn_Title = "Title";
    private static final String Hymn_Text = "Text";
    private SQLiteDatabase database;

ListView list;
EditText search;
HymnsAdapter vadapter;
ArrayList<Hymns> HymnsList;
String url;
Context context=null;


public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // TODO Auto-generated method stub
      return inflater.inflate(R.layout.index, container,false);
}


@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    list = (ListView)getActivity().findViewById(R.id.hymn_list);
    search = (EditText) getActivity().findViewById(R.id.search);
    HymnsList = new ArrayList<Hymns>();

    DatabaseHelper dbOpenHelper = new DatabaseHelper(getActivity(), DB_NAME);
    database = dbOpenHelper.openDataBase();

    fillHymns();
    //setUpList();

}



private void fillHymns() {
    Cursor hymnCursor = database.query(TABLE_NAME,
                                         new String[] 
                                         {Hymn_ID, Hymn_Title,Hymn_Text},
                                         null, null, null, null
                                         , Hymn_Title);
    hymnCursor.moveToFirst();
    if(!hymnCursor.isAfterLast()) {
        do {
            Hymns hy = new Hymns();
            hy.setTitle(hymnCursor.getString(1));
            hy.setText(hymnCursor.getString(2));
            HymnsList.add(hy);

        } while (hymnCursor.moveToNext());
    }
    hymnCursor.close();
     vadapter = new HymnsAdapter(getActivity().getApplicationContext(),R.layout.hymns,HymnsList);
    list.setAdapter(vadapter);

    list.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {

            Intent intent = new Intent(getActivity().getApplicationContext(), Hymn_Text.class);
            intent.putExtra("Title",HymnsList.get(position).getTitle());
            intent.putExtra("Text",HymnsList.get(position).getText());
            startActivity(intent);
            //Log.i("Text",HymnsList.get(position).getText());

        }








    });


    search.addTextChangedListener( new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence cs, int start, int before, int count) {
            // TODO Auto-generated method stub
            if(count>0){


            }

        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub
             Home.this.vadapter.getFilter().filter(s);
                Log.i("Changed",s.toString());
        }
    });
}




  }

The log,logs whatever input i type in,but doesn't show the listview. Thank you

This question is related to android android-listview custom-adapter

The answer is


Just an update.

If the ticked answer is working fine for you but it shows nothing when the search text is empty. Here is the solution:

private class ItemFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        
        String filterString = constraint.toString().toLowerCase();
        
        FilterResults results = new FilterResults();

        if(constraint.length() == 0)
        {
            results.count = originalData.size();
            results.values = originalData;
        }else {

        
        final List<String> list = originalData;

        int count = list.size();
        final ArrayList<String> nlist = new ArrayList<String>(count);

        String filterableString ;
        
        for (int i = 0; i < count; i++) {
            filterableString = list.get(i);
            if (filterableString.toLowerCase().contains(filterString)) {
                nlist.add(filterableString);
            }
        }
        
        results.values = nlist;
        results.count = nlist.size();
     }
        return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        filteredData = (ArrayList<String>) results.values;
        notifyDataSetChanged();
      }

   }

For any query comment below


If you want to achieve filtering with custom model class in kotlin then you can implement below code.

Step 1: Add SearchView in your xml file and then in your activity or fragment implement SearchView.OnQueryTextListener

class SearchActivity : AppCompatActivity(),SearchView.OnQueryTextListener {


    lateinit var sectionModelArrayList: ArrayList<CategorySectionModel>
    lateinit var filteredArrayList: ArrayList<CategorySectionModel>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_category_updated)
        searchView.setOnQueryTextListener(this)
    }


    //Called this method with you own data to populate the recycler view.
    private fun parseJson() {
        rv_category_list.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
        adapter = CategoryLabelAdapter(sectionModelArrayList, this)
        rv_category_list.adapter = adapter
    }

    override fun onQueryTextSubmit(query: String?): Boolean {
        return false
    }

    override fun onQueryTextChange(newText: String?): Boolean {
        adapter.filter!!.filter(newText.toString())
        return false
    }

My model class CategorySectionModel looks like

class CategorySectionModel(val categoryLabel: String, val categoryItemList: ArrayList<CategoryItem>)

Now we have to work on adapter class and there you need to implement Filterable interface and override getFilter() method like below

class CategoryLabelAdapter(internal var data: ArrayList<CategorySectionModel>?, internal var activity: Context) : RecyclerView.Adapter<CategoryLabelAdapter.ViewHolder>(), Filterable {
    val originalList = data
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.item_category_name, parent, false)
        return ViewHolder(v)
    }

    override fun getItemCount(): Int {
        return data!!.size
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        data?.get(position)?.let { holder.bindItem(it) }
    }


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        @SuppressLint("SetTextI18n")
        fun bindItem(data: CategorySectionModel) {
            itemView.tv_category_name.text = data.categoryLabel
        }
    }

    override fun getFilter(): Filter? {
        return object : Filter() {
            override fun performFiltering(constraint: CharSequence): FilterResults {
                val results = FilterResults()
                if (constraint.isEmpty()) {
                    //no filter implemented we return full list
                    results.values = data
                    results.count = data!!.size
                } else {
                    //Here we perform filtering operation
                    val list: ArrayList<CategorySectionModel> = ArrayList()
                    for (p in data!!) {
                        if (p.categoryLabel.toUpperCase().startsWith(constraint.toString().toUpperCase())) list.add(p)
                    }
                    results.values = list
                    results.count = list.size
                }
                return results
            }

            override fun publishResults(constraint: CharSequence, results: FilterResults) {
                // Now we have to inform the adapter about the new list filtered
                if (results.count == 0 || constraint == "") {
                    data = originalList
                    notifyDataSetChanged()
                } else {
                    data = results.values as ArrayList<CategorySectionModel>?
                    notifyDataSetChanged()
                }
            }
        }
    }
}

You can implement search filter in listview by two ways. 1. using searchview 2. using edittext.

  1. If yo want to use searchview then read here : searchview filter.

  2. If you want to use edittext, read below.

I have taken reference from : listview search filter android

Code snippets to make filter with edittext.

First create model class MovieNames.java:

public class MovieNames {
    private String movieName;

    public MovieNames(String movieName) {
        this.movieName = movieName;
    }

    public String getMovieName() {
        return this.movieName;
    }

}

Create listview_item.xml file :

     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp">


    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

Make ListViewAdapter.java class :

    import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Locale;

public class ListViewAdapter extends BaseAdapter {

    // Declare Variables

    Context mContext;
    LayoutInflater inflater;
    private ArrayList<MovieNames> arraylist;

    public ListViewAdapter(Context context, ArrayList<MovieNames> arraylist) {
        mContext = context;
        inflater = LayoutInflater.from(mContext);
        this.arraylist = arraylist;

    }

    public class ViewHolder {
        TextView name;
    }

    @Override
    public int getCount() {
        return arraylist.size();
    }

    @Override
    public MovieNames getItem(int position) {
        return arraylist.get(position);
    }

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

    public View getView(final int position, View view, ViewGroup parent) {
        final ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.listview_item, null);
            // Locate the TextViews in listview_item.xml
            holder.name = (TextView) view.findViewById(R.id.name);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
        // Set the results into TextViews
        holder.name.setText(arraylist.get(position).getMovieName());
        return view;
    }


} 

Prepare activity_main.xml file :

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    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"
    tools:context="com.example.parsaniahardik.searchedit.MainActivity"
    android:orientation="vertical">


    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:hint="enter query"
        android:singleLine="true">


        <requestFocus/>
    </EditText>

    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/listView"
        android:divider="#694fea"
        android:dividerHeight="1dp" />


</LinearLayout>

Finally make MainActivity.java class :

    import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private EditText etsearch;
    private ListView list;
    private ListViewAdapter adapter;
    private String[] moviewList;
    public static ArrayList<MovieNames> movieNamesArrayList;
    public static ArrayList<MovieNames> array_sort;
    int textlength = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Generate sample data

        moviewList = new String[]{"Xmen", "Titanic", "Captain America",
                "Iron man", "Rocky", "Transporter", "Lord of the rings", "The jungle book",
                "Tarzan","Cars","Shreck"};

        list = (ListView) findViewById(R.id.listView);

        movieNamesArrayList = new ArrayList<>();
        array_sort = new ArrayList<>();

        for (int i = 0; i < moviewList.length; i++) {
            MovieNames movieNames = new MovieNames(moviewList[i]);
            // Binds all strings into an array
            movieNamesArrayList.add(movieNames);
            array_sort.add(movieNames);
        }

        adapter = new ListViewAdapter(this,movieNamesArrayList);
        list.setAdapter(adapter);


        etsearch = (EditText) findViewById(R.id.editText);

        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this, array_sort.get(position).getMovieName(), Toast.LENGTH_SHORT).show();
            }
        });

        etsearch.addTextChangedListener(new TextWatcher() {


            public void afterTextChanged(Editable s) {
            }

            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            public void onTextChanged(CharSequence s, int start, int before, int count) {
                textlength = etsearch.getText().length();
                array_sort.clear();
                for (int i = 0; i < movieNamesArrayList.size(); i++) {
                    if (textlength <= movieNamesArrayList.get(i).getMovieName().length()) {
                        Log.d("ertyyy",movieNamesArrayList.get(i).getMovieName().toLowerCase().trim());
                        if (movieNamesArrayList.get(i).getMovieName().toLowerCase().trim().contains(
                                etsearch.getText().toString().toLowerCase().trim())) {
                            array_sort.add(movieNamesArrayList.get(i));
                        }
                    }
                }
                    adapter = new ListViewAdapter(MainActivity.this, array_sort);
                    list.setAdapter(adapter);

            }
        });

    }
}

please check below code it will help you

DrawerActivity.userListview
            .setOnItemClickListener(new OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {

                    int pos = position;
                    Intent intent = new Intent(getContext(),
                            UserDetail.class);
                    intent.putExtra("model", list.get(position));
                    context.startActivity(intent);
                }
            });
    return convertView;
}

@Override
public android.widget.Filter getFilter() {

    return new android.widget.Filter() {

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

            ArrayList<UserListModel> updatelist = (ArrayList<UserListModel>) results.values;
            UserListCustomAdaptor newadaptor = new UserListCustomAdaptor(
                    getContext(), getCount(), updatelist);

            if (results.equals(constraint)) {
                updatelist.add(modelobj);
            }
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {

                notifyDataSetInvalidated();
            }
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

            FilterResults filterResults = new FilterResults();
            list = new ArrayList<UserListModel>();

            if (constraint != null && DrawerActivity.userlist != null) {

                constraint = constraint.toString().toLowerCase();
                int length = DrawerActivity.userlist.size();
                int i = 0;
                while (i < length) {

                    UserListModel modelobj = DrawerActivity.userlist.get(i);
                    String data = modelobj.getFirstName() + " "
                            + modelobj.getLastName();
                    if (data.toLowerCase().contains(constraint.toString())) {
                        list.add(modelobj);
                    }

                    i++;
                }
                filterResults.values = list;
                filterResults.count = list.size();
            }
            return filterResults;
        }
    };
}

@Override
public int getCount() {
    return list.size();
}

@Override
public UserListModel getItem(int position) {

    return list.get(position);
}

you can find custom list adapter class with filterable using text change in edit text...

create custom list adapter class with implementation of Filterable:

private class CustomListAdapter extends BaseAdapter implements Filterable{

    private LayoutInflater inflater;
    private ViewHolder holder;
    private ItemFilter mFilter = new ItemFilter();

    public CustomListAdapter(List<YourCustomData> newlist) {
        filteredData = newlist;
    }

    @Override
    public int getCount() {
        return filteredData.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

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

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

        holder = new ViewHolder();

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

        if(convertView == null){
            convertView = inflater.inflate(R.layout.row_listview_item, null);

            holder.mTextView = (TextView)convertView.findViewById(R.id.row_listview_member_tv);

            convertView.setTag(holder);
        }else{
            holder = (ViewHolder)convertView.getTag();
        }

        holder.mTextView.setText(""+filteredData.get(position).getYourdata());

        return convertView;
    }

    @Override
    public Filter getFilter() {
        return mFilter;
    }


}

class ViewHolder{
    TextView mTextView;
}

private class ItemFilter extends Filter {
    @SuppressLint("DefaultLocale")
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {

        String filterString = constraint.toString().toLowerCase();

        FilterResults results = new FilterResults();

        final List<YourCustomData> list = YourObject.getYourDataList();

        int count = list.size();
        final ArrayList<YourCustomData> nlist = new ArrayList<YourCustomData>(count);

        String filterableString ;

        for (int i = 0; i < count; i++) {
            filterableString = ""+list.get(i).getYourText();
            if (filterableString.toLowerCase().contains(filterString)) {
                YourCustomData mYourCustomData = list.get(i);
                nlist.add(mYourCustomData);
            }
        }

        results.values = nlist;
        results.count = nlist.size();

        return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        filteredData = (ArrayList<YourCustomData>) results.values;
        mCustomListAdapter.notifyDataSetChanged();
    }

}

mEditTextSearch.addTextChangedListener(new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if(mCustomListAdapter!=null)
                mCustomListAdapter.getFilter().filter(s.toString());

        }
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }
        @Override
        public void afterTextChanged(Editable s) {
        }
    });

First you create the EditText in the xml file and assign an id, eg con_pag_etPesquisa. After that, we will create two lists, where one is the list view and the other to receive the same content but will remain as a backup. Before moving objects to lists first initializes Them the below:

//Declaring

public EditText etPesquisa;

public ContasPagarAdapter adapterNormal;

public List<ContasPagar> lstBkp;

public List<ContasPagar> lstCp;

//Within the onCreate method, type the following:

etPesquisa = (EditText) findViewById(R.id.con_pag_etPesquisa);

etPesquisa.addTextChangedListener(new TextWatcher(){

    @Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3){
        filter(String.valueOf(cs));
    }
    @Override
    public void beforeTextChanged(CharSequence cs, int arg1, int arg2, int arg3){

    // TODO Auto-generated method stub
    }
    @Override
    public void afterTextChanged(Editable e){

    }

});

//Before moving objects to lists first initializes them as below:

lstCp = new ArrayList<ContasPagar>();

lstBkp = new ArrayList<ContasPagar>();


//When you add objects to the main list, repeat the procedure also for bkp list, as follows:

lstCp.add(cp);

lstBkp.add(cp);


//Now initializes the adapter and let the listener, as follows:

adapterNormal = new ContasPagarAdapter(ContasPagarActivity.this, lstCp);

lvContasPagar.setAdapter(adapterNormal);
                    lvContasPagar.setOnItemClickListener(verificaClickItemContasPagar(lstCp));


//Now create the methods inside actito filter the text entered by the user, as follows:

public void filter(String charText){

    charText = charText.toLowerCase();

    lstCp.clear();

    if (charText.length() == 0){

        lstCp.addAll(lstBkp);

        appendAddItem(lstBkp);

    } 

    else {

        for (int i = 0; i < lstBkp.size(); i++){

            if((lstBkp.get(i).getNome_lancamento() + " - " + String.valueOf(lstBkp.get(i).getCodigo())).toLowerCase().contains(charText)){

                lstCp.add(lstBkp.get(i));

            }

        }

        appendAddItem(lstCp);
    }
}

private void appendAddItem(final List<ContasPagar> novaLista){
    runOnUiThread(new Runnable(){

        @Override
            public void run(){
                adapterNormal.notifyDataSetChanged();               
            }
        });
    }

One thing I've noticed is that whenever you are editing the list (adding items for example) as well as filtering for it, then inside the @Override getView method, you shouldn't use filteredData.get(position), as it throws an IndexOutOfBounds exception.

Instead, what worked for me, was using the getItem(position) method, which belongs to the ArrayAdapter class.


I hope it will be helpful for others.

// put below code (method) in Adapter class
public void filter(String charText) {
    charText = charText.toLowerCase(Locale.getDefault());
    myList.clear();
    if (charText.length() == 0) {
        myList.addAll(arraylist);
    }
    else
    {
        for (MyBean wp : arraylist) {
            if (wp.getName().toLowerCase(Locale.getDefault()).contains(charText)) {
                myList.add(wp);
            }
        }
    }
    notifyDataSetChanged();
}

declare below code in adapter class

private ArrayList<MyBean> myList;  // for loading main list
private ArrayList<MyBean> arraylist=null;  // for loading  filter data

below code in adapter Constructor

this.arraylist = new ArrayList<MyBean>();
    this.arraylist.addAll(myList);

and below code in your activity class

final EditText searchET = (EditText)findViewById(R.id.search_et);
    // Capture Text in EditText
    searchET.addTextChangedListener(new TextWatcher() {

        @Override
        public void afterTextChanged(Editable arg0) {
            // TODO Auto-generated method stub
            String text = searchET.getText().toString().toLowerCase(Locale.getDefault());
            adapter.filter(text);
        }

        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1,
                                      int arg2, int arg3) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onTextChanged(CharSequence arg0, int arg1, int arg2,
                                  int arg3) {
            // TODO Auto-generated method stub
        }
    });

In your CustomAdapter class implement filterable.

listview with search search listview

 public class CustomAdapter extends BaseAdapter implements Filterable {

    private List<ItemsModel> itemsModelsl;
    private List<ItemsModel> itemsModelListFiltered;
    private Context context;

    public CustomAdapter(List<ItemsModel> itemsModelsl, Context context) {
        this.itemsModelsl = itemsModelsl;
        this.itemsModelListFiltered = itemsModelsl;
        this.context = context;
    }



    @Override
    public int getCount() {
        return itemsModelListFiltered.size();
    }

    @Override
    public Object getItem(int position) {
        return itemsModelListFiltered.get(position);
    }

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view = getLayoutInflater().inflate(R.layout.row_items,null);


        TextView names = view.findViewById(R.id.name);
        TextView emails = view.findViewById(R.id.email);
        ImageView imageView = view.findViewById(R.id.images);

        names.setText(itemsModelListFiltered.get(position).getName());
        emails.setText(itemsModelListFiltered.get(position).getEmail());
        imageView.setImageResource(itemsModelListFiltered.get(position).getImages());

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("main activity","item clicked");
                startActivity(new Intent(MainActivity.this,ItemsPreviewActivity.class).putExtra("items",itemsModelListFiltered.get(position)));

            }
        });

        return view;
    }



    @Override
    public Filter getFilter() {
        Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {

                FilterResults filterResults = new FilterResults();
                if(constraint == null || constraint.length() == 0){
                    filterResults.count = itemsModelsl.size();
                    filterResults.values = itemsModelsl;

                }else{
                    List<ItemsModel> resultsModel = new ArrayList<>();
                    String searchStr = constraint.toString().toLowerCase();

                    for(ItemsModel itemsModel:itemsModelsl){
                        if(itemsModel.getName().contains(searchStr) || itemsModel.getEmail().contains(searchStr)){
                            resultsModel.add(itemsModel);

                        }
                         filterResults.count = resultsModel.size();
                            filterResults.values = resultsModel;
                    }


                }

                return filterResults;
            }

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

                itemsModelListFiltered = (List<ItemsModel>) results.values;
                notifyDataSetChanged();

            }
        };
        return filter;
    }
}

}

You can get the whole tutorial here: ListView With Search/Filter and OnItemClickListener

Github Source Code