Search code examples
androidandroid-listviewcustom-adapter

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


Solution

  • You can use the Filterable interface on your Adapter, have a look at the example below:

    public class SearchableAdapter extends BaseAdapter implements Filterable {
        
        private List<String>originalData = null;
        private List<String>filteredData = null;
        private LayoutInflater mInflater;
        private ItemFilter mFilter = new ItemFilter();
        
        public SearchableAdapter(Context context, List<String> data) {
            this.filteredData = data ;
            this.originalData = data ;
            mInflater = LayoutInflater.from(context);
        }
     
        public int getCount() {
            return filteredData.size();
        }
     
        public Object getItem(int position) {
            return filteredData.get(position);
        }
     
        public long getItemId(int position) {
            return position;
        }
     
        public View getView(int position, View convertView, ViewGroup parent) {
            // A ViewHolder keeps references to children views to avoid unnecessary calls
            // to findViewById() on each row.
            ViewHolder holder;
     
            // When convertView is not null, we can reuse it directly, there is no need
            // to reinflate it. We only inflate a new View when the convertView supplied
            // by ListView is null.
            if (convertView == null) {
                convertView = mInflater.inflate(R.layout.list_item, null);
     
                // Creates a ViewHolder and store references to the two children views
                // we want to bind data to.
                holder = new ViewHolder();
                holder.text = (TextView) convertView.findViewById(R.id.list_view);
     
                // Bind the data efficiently with the holder.
     
                convertView.setTag(holder);
            } else {
                // Get the ViewHolder back to get fast access to the TextView
                // and the ImageView.
                holder = (ViewHolder) convertView.getTag();
            }
     
            // If weren't re-ordering this you could rely on what you set last time
            holder.text.setText(filteredData.get(position));
     
            return convertView;
        }
        
        static class ViewHolder {
            TextView text;
        }
     
        public Filter getFilter() {
            return mFilter;
        }
     
        private class ItemFilter extends Filter {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                
                String filterString = constraint.toString().toLowerCase();
                
                FilterResults results = new FilterResults();
                
                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();
            }
     
        }
    }
    

    In your Activity or Fragment where of Adapter is instantiated :

    editTxt.addTextChangedListener(new TextWatcher() {
      
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            System.out.println("Text ["+s+"]");
            
            mSearchableAdapter.getFilter().filter(s.toString());                           
        }
         
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
             
        }
         
        @Override
        public void afterTextChanged(Editable s) {
        }
    });
    

    Here are the links for the original source and another example