Search code examples
androidlistviewandroid-fragmentsandroid-adapterandroid-filterable

Searching in a listview using a Custom Adapter with text and images


I am configuring a resource in my app to search in a Listview using a custom Adapter. I using an EditText to type the string and passing the text to Adapter on addTextChangedListener Event, but it is not working.

I configure the adapter with "implements Filterable" and enable Listview with ".setTextFilterEnabled(true)", but doesn´t work.

I saw that I must implement "public Filter getFilter()" but I have no idea how can I do that.

When I type some words in EditText, like "cel" or "12" the filter goes in action, but the result is always the same: The first two items in Listview, no matter what is into the Listview (the content of listview is random).

Below a snippet of my Fragment Activity:

public class VideosFragment extends Fragment {

private ListView listView;
private ArrayList<String> idVideo = new ArrayList<>();
private ArrayList<String> titleVideo = new ArrayList<>();
private ArrayList<String> descVideo = new ArrayList<>();
private ArrayList<String> urlVideo = new ArrayList<>();
private ArrayList<String> channelTitle = new ArrayList<>();
private ArrayList<String> canalTitle = new ArrayList<>();
private ArrayList<String> canalId = new ArrayList<>();
private CustomFiltraCanaisAdapter customFiltraCanaisAdapter;
private EditText editText;

CustomVideoAdapter customVideoAdapter;

public VideosFragment() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_videos, container, false);


    // Configure Listview
    listView = (ListView)view.findViewById(R.id.listView_videos);

    //Create search parameters
    editText = (EditText) view.findViewById(R.id.searchList);
    listView.setTextFilterEnabled(true);
    editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            String text = editText.getText().toString().toLowerCase(Locale.getDefault());
            VideosFragment.this.customVideoAdapter.getFilter().filter(text);
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    });

and below my CustomAdapter:

public class CustomVideoAdapter extends ArrayAdapter<String> implements Filterable {

private final Activity context;
private final ArrayList<String> videoTitle;
private final ArrayList<String> videoDesc;
private final ArrayList<String> videoId;
private final ArrayList<String> channelTitle;
private final ArrayList<String> imgurl;

public CustomVideoAdapter(Activity context, ArrayList<String> videoTitle,
                                            ArrayList<String> videoId,
                                            ArrayList<String> channelTitle,
                                            ArrayList<String> imgurl,
                                            ArrayList<String> videoDesc) {
    super(context, R.layout.custom_lista_videos, videoTitle);
    // TODO Auto-generated constructor stub

    this.context = context;
    this.videoTitle = videoTitle;
    this.videoDesc = videoDesc;
    this.videoId = videoId;
    this.channelTitle = channelTitle;
    this.imgurl = imgurl;
}
public View getView(int position,View view,ViewGroup parent) {
    LayoutInflater inflater=context.getLayoutInflater();
    View rowView=inflater.inflate(R.layout.custom_lista_videos, null,true);

    TextView txtTitle = (TextView) rowView.findViewById(R.id.txtVideoTitle);
    ImageView imgPhoto = (ImageView) rowView.findViewById(R.id.imgPhoto);
    TextView txtChannelTitle = (TextView) rowView.findViewById(R.id.txtChannelTitle);
    TextView txtVideoId = (TextView) rowView.findViewById(R.id.txtVideoId);
    TextView txtVideoDesc = (TextView) rowView.findViewById(R.id.txtVideoDesc);

    txtTitle.setText(videoTitle.get(position));
    Picasso.with(context).load(imgurl.get(position)).into(imgPhoto);
    txtChannelTitle.setText(channelTitle.get(position));
    txtVideoId.setText(videoId.get(position));
    txtVideoDesc.setText(videoDesc.get(position));
    return rowView;

};

What is missing?

After some helps I trying to create (and use) a Model Class, but I still have no progress because I did not figure out how can I must change my code on "CustomAdapter" to use correctly this code.

My Model Class is below:

public class FilteredVideoAdapter {

private ArrayList<String> storedVideoTitle = null;
private ArrayList<String> storedVideoDesc = null;
private ArrayList<String> storedVideoId = null;
private ArrayList<String> storedChannelTitle = null;
private ArrayList<String> storedImgurl = null;

public FilteredVideoAdapter(){

}

public ArrayList<String> getStoredVideoTitle() {
    return storedVideoTitle;
}

public void setStoredVideoTitle(ArrayList<String> storedVideoTitle) {
    this.storedVideoTitle = storedVideoTitle;
}

public ArrayList<String> getStoredVideoDesc() {
    return storedVideoDesc;
}

public void setStoredVideoDesc(ArrayList<String> storedVideoDesc) {
    this.storedVideoDesc = storedVideoDesc;
}

public ArrayList<String> getStoredVideoId() {
    return storedVideoId;
}

public void setStoredVideoId(ArrayList<String> storedVideoId) {
    this.storedVideoId = storedVideoId;
}

public ArrayList<String> getStoredChannelTitle() {
    return storedChannelTitle;
}

public void setStoredChannelTitle(ArrayList<String> storedChannelTitle) {
    this.storedChannelTitle = storedChannelTitle;
}

public ArrayList<String> getStoredImgurl() {
    return storedImgurl;
}

public void setStoredImgurl(ArrayList<String> storedImgurl) {
    this.storedImgurl = storedImgurl;
}

public FilteredVideoAdapter withFilteredVideoAdapter(
        ArrayList<String> storedVideoTitle,
        ArrayList<String> storedVideoDesc,
        ArrayList<String> storedVideoId,
        ArrayList<String> storedChannelTitle,
        ArrayList<String> storedImgurl){

    this.storedVideoTitle = storedVideoTitle;
    this.storedVideoDesc = storedVideoDesc;
    this.storedVideoId = storedVideoId;
    this.storedChannelTitle = storedChannelTitle;
    this.storedImgurl = storedImgurl;

    return this;
}

}


Solution

  • This is what you have to do inside your adapter, you might need to do some tweaks:-

     @Override
        public Filter getFilter() {
            return new Filter() {
                @Override
                protected FilterResults performFiltering(CharSequence constraint) {
                    FilterResults results = new FilterResults();
    
    
    
                    // If the constraint (search string/pattern) is null
                    // or its length is 0, i.e., its empty then
                    // we just set the `values` property to the
                    // original contacts list which contains all of them
                    if (constraint == null || constraint.length() == 0) {
                        results.values =   videoTitle;;
                        results.count = videoTitle.size();
                    }
                    else {
                        // Some search copnstraint has been passed
                        // so let's filter accordingly
                        ArrayList<String> filteredTitle = new ArrayList<String>();
    
                        // We'll go through all the title and see
                        // if they contain the supplied string
                        for (String c : string) {
                            if (string.toUpperCase().contains( constraint.toString().toUpperCase() )) {
                                // if `contains` == true then add it
                                // to our filtered list
                                filteredTitle.add(c);
                            }
                        }
    
                        // Finally set the filtered values and size/count
                        results.values = filteredTitle;
                        results.count = filteredTitle.size();
                    }
    
                    // Return our FilterResults object
                    return results;
                }
                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    mList = (ArrayList<String>) results.values;
                    notifyDataSetChanged();
                }
            };
        }
    

    Hope this will help you.