Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android. Search and filter in the RecyclerView

translated using "google translate"!

Briefly about the problem. I decided to try to use RecyclerView. Ready solutions like search listView, there is no need to implement all. So I found a solution, if one is needed at the bottom of the source code, but there is a problem. There is a list, it displays headlines, when you click on any item in the second turn Activiti which already has a title and a full description. Realized I like: In MainActivity I load from the database (using Sugar ORM) headers and id

ArrayList<String> arrTitle = new ArrayList<>();
for(Contact contact:allContacts){
arrTitle.add(contact.title);
}

ArrayList<String> arrId = new ArrayList<>();
for(Contact contact:allContacts){
long  i = contact.getId();
String str = Long.toString(i);
arrId.add(str);
}

Then convey them to the adapter

mAdapter = new RecyclerAdapter(arrTitle,  arrId);

The adapter Recycler Adapter I get the value deduce heading into the list, and the second pass id Activity

        @Override
public void onBindViewHolder(ViewHolder holder, int position) {

// Convert the id to the array
idTab = new String[mId.size()];
for (int i = 0; i != mId.size(); i++) {
    idTab[i] = mId.get(i);
}

// Element position
final int idvadaptere = position;
// Display headers RecyclerView
holder.mTextView.setText(mDataset.get(position));

holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Context context = v.getContext();
        Intent ddddd = new Intent(context, LastActivity.class);
        ddddd.putExtra("id", idTab[idvadaptere]);
        context.startActivity(ddddd);
    }
});
}

In the second Activiti LastActivity I get the id and on the basis of this id already deduce values in the text field

// Get the Intent extract from it an object
// Extract from it an object
idString = intent.getStringExtra("id");
// Convert the id in number
idInt = Integer.parseInt(idString);


// Display the text fields
Contact title = Contact.findById(Contact.class, idInt);
String titleStr = title.title;
textView.setText(titleStr);

Contact prich = Contact.findById(Contact.class, idInt);
String prichStr = prich.prich;
textView2.setText(prichStr);

The problem is that, if put into finding a header, the header position of this list will not be the fifth, for example, and the first and id have to be different to a second value aktiviti not expose the fifth id, and from the first. The source search, it works fine if you need to copy anyone, the only problem is the transmission of data by clicking on a list item.

activity_main.xml

<android.support.v7.widget.SearchView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:id="@+id/search_view"
  android:layout_gravity="right"
  app:theme="@style/Theme.AppCompat.NoActionBar"
  app:searchIcon="@drawable/ic_search_white_24dp"/>

MainActivity.java

 private SearchView searchView;

In onCreate

searchView = (SearchView) findViewById(R.id.search_view);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String text) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String text) {
        mAdapter.filter(text);
        return false;
    }
});

RecyclerAdapter.java

private ArrayList<String> mDataset;
private ArrayList<String> mCleanCopyDataset;

Constructor

public RecyclerAdapter(ArrayList<String> dataset) {
mDataset = dataset;
mCleanCopyDataset = mDataset;
}

Search

      // The filter () method we iterate through all the items on the list and if any item contains the search text, we add it to a new list mDataset:

public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
mDataset = new ArrayList<String>();
if (charText.length() == 0) {
    // mCleanCopyDataset we always contains the unaltered and the filter (full) copy of the list of data
    mDataset.addAll(mCleanCopyDataset);
} else {
    for (String item : mCleanCopyDataset) {

       // we iterate through all the items on the list and if any item contains the search text, we add it to a new list mDataset
        if (item.toLowerCase(Locale.getDefault()).contains(charText)) {
            mDataset.add(item);
        }
    }
}
// method notifyDataSetChanged () allows you to update the list on the screen after filtration
notifyDataSetChanged();
}

full code RecyclerAdapter.java

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {

private ArrayList<String> mDataset;
private ArrayList<String> mId;
private ArrayList<String> mCleanCopyDataset;
String[] idTab;
String[] titleTab;

public static class ViewHolder extends RecyclerView.ViewHolder {
    public TextView mTextView;

    public ViewHolder(View v) {
        super(v);
        mTextView = (TextView) v.findViewById(R.id.tv_recycler_item);
    }
}

public RecyclerAdapter(ArrayList<String> dataset, String[] titleTab, ArrayList<String> id) {
    mDataset = dataset;
    titleTab = titleTab;
    mId = id;
    mCleanCopyDataset = mDataset;
}

@Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                     int viewType) {
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.recycler_item, parent, false);


    ViewHolder vh = new ViewHolder(v);
    return vh;
}


@Override
public void onBindViewHolder(final ViewHolder holder, int position) {

    idTab = new String[mId.size()];
    for (int i = 0; i != mId.size(); i++) {
        idTab[i] = mId.get(i);
    }

     holder.mTextView.setText(mDataset.get(position));

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Context context = v.getContext();
            Intent ddddd = new Intent(context, LastActivity.class);
            ddddd.putExtra("id", idTab[holder.getAdapterPosition()]);
            context.startActivity(ddddd);
        }
    });
}


@Override
public int getItemCount() {
    return mDataset.size();
}



public void filter(String charText) {
    charText = charText.toLowerCase(Locale.getDefault());
    mDataset = new ArrayList<String>();
    if (charText.length() == 0) {

        mDataset.addAll(mCleanCopyDataset);
    } else {
        for (String item : mCleanCopyDataset) {

            if (item.toLowerCase(Locale.getDefault()).contains(charText)) {
                mDataset.add(item);
            }
        }
    }
    notifyDataSetChanged();
}

}

enter image description here

enter image description here

like image 282
Artsait Avatar asked Dec 24 '22 01:12

Artsait


1 Answers

You should use Android's built in ability to filter your recycler views.

To do this, make your RecyclerAdapter implement filterable.

public class MyAdapter extends RecyclerVew.Adapter implements Filterable {

    private MyFilter filter;

    public MyAdapter() {
        // Do stuff
    }

    @Override
    public Filter getFilter() {
        if (filter == null) {
            filter = new MyFilter(this, getElements());
        }
        return filter;
    }

You'll notice in this code sample, I have something called MyFilter. This is something you will create and provide custom logic for.

Here is just one example.

private static class MyFilter extends Filter {

    private final MyAdapter adapter;
    private final List<String> originalList;
    private final List<String> filteredList;

    private MyFilter(MyAdapter adapter, List<String> originalList) {
        super();
        this.adapter = adapter;
        this.originalList = new LinkedList<>(originalList);
        this.filteredList = new ArrayList<>();
    }

    @Override
    protected FilterResults performFiltering(CharSequence charSequence) {
        filteredList.clear();
        final FilterResults results = new FilterResults();

        if (charSequence.length() == 0) {
            filteredList.addAll(originalList);
        } else {
            final String filterPattern = charSequence.toString().toLowerCase().trim();
            for (String item : originalList) {
                if (item.toLowerCase().contains(filterPattern) {
                    filteredList.add(item);
                }
            }
        }

        results.values = filteredList;
        results.count = filteredList.size();
        return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
        mDataset.clear();
        mDataset.add(filterResults.values);
        adapter.notifyDataSetChanged();
    }
}

Then in your onQueryTextChange method, call the filter.

@Override
public boolean onQueryTextChange(String text) {
    mAdapter.getFilter().filter(text);
    return false;
}
like image 123
Weava Avatar answered Dec 26 '22 15:12

Weava