Добавить фильтр на RecyclerView с карточками?

Я нашел решения для фильтров на ListView и SearchView на RecyclerView отдельно, но я хочу их объединить. Возможно ли это?

Ответ 1

Да, возможно, ваш RecyclerView.Adapter может реализовать Filterable. После этого вам нужно переопределить метод Filter getFilter().

Вы должны определить свой собственный фильтр, как показано в приведенном ниже коде:

@Override
public Filter getFilter() {
    return new YourFilterClass();
}

YourFilterClass

class YourFilterClass extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            //Here you have to implement filtering way
            final FilterResults results = new FilterResults();
            //logic to filtering
            results.values = ...
            results.count = ...
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            // here you can use result - (f.e. set in in adapter list)
        }
}

Пример

public class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.ViewHolder> implements Filterable {

    private final List<User> userList;

    private final List<User> filteredUserList;

    private UserFilter userFilter;

    public UserListAdapter(Context context) {
        this.userList =new ArrayList<>();
        this.filteredUserList = new ArrayList<>();
    }


    ///... other methods

    @Override
    public Filter getFilter() {
       if(userFilter == null)
             userFilter = new UserFilter(this, userList);
        return userFilter;
    }

    private static class UserFilter extends Filter {

        private final UserListAdapter adapter;

        private final List<User> originalList;

        private final List<User> filteredList;

        private UserFilter(UserListAdapter adapter, List<User> originalList) {
            super();
            this.adapter = adapter;
            this.originalList = new LinkedList<>(originalList);
            this.filteredList = new ArrayList<>();
        }

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

            if (constraint.length() == 0) {
                filteredList.addAll(originalList);
            } else {
                final String filterPattern = constraint.toString().toLowerCase().trim();

                for (final User user : originalList) {
                    if (user.getName().contains(filterPattern)) {
                        filteredList.add(user);
                    }
                }
            }
            results.values = filteredList;
            results.count = filteredList.size();
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            adapter.filteredUserList.clear();
            adapter.filteredUserList.addAll((ArrayList<User>) results.values);
            adapter.notifyDataSetChanged();
        }
    }
}

После этого в том месте, где вы хотите отфильтровать вызов:

userListAdapter.getFilter().filter(text)

Ответ 2

Внутри Fragment Class объявить, что:

protected List<User> mDataset;
protected List<User> mDataOrigin;

затем внутри onCreate добавить тот же источник адресата как для dataSet ant dataOrigin

mDataset = getObjectsFromDB();
mDataOrigin = getObjectsFromDB();

Наконец, используйте магическую функцию:

private void filterRecyclerView(String charText){
    charText = charText.toLowerCase();
    clearDataSet();
    if (charText.length() == 0) {
        mDataset.addAll(mDataOrigin);
    } else {
        for (User user : mDataOrigin) {
            if (user.getName().toLowerCase().contains(charText)) {
                mDataset.add(user);
            }
        }
    }
    mAdapter.notifyDataSetChanged();
}

Примечание User - это содержимое списка, которое вы можете заменить своим объектом, весело:)

Ответ 3

Вот полный пример кода

Класс модели

public class Skills {

    int id;
    String skill;
    boolean isSelected;

    public boolean isSelected() {
        return isSelected;
    }

    public void setSelected(boolean selected) {
        isSelected = selected;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }
}

Класс адаптера

private static final String TAG = SkillAdapter.class.getSimpleName();
    protected List<Skills> mOriginalData = new ArrayList<>();
    protected List<Skills> mResultData = new ArrayList<>();

    protected Activity mActivity;
    OnRecyclerViewClick onRecyclerViewClick;
    private ItemFilter mFilter = new ItemFilter();

    public SkillAdapter(Activity activity, OnRecyclerViewClick onRecyclerViewClick) {
        mActivity = activity;
        this.onRecyclerViewClick = onRecyclerViewClick;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_skill,
                parent, false);

        return new ViewHolder(view);
    }

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

        final Skills data = mResultData.get(position);
        try {
            final ViewHolder viewHolder = (ViewHolder) holder;

            if (data != null) {
                viewHolder.checkSkill.setText(data.getSkill());
                viewHolder.checkSkill.setChecked(data.isSelected());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

    public void addItem(Skills exam) {
        mOriginalData.add(exam);
        mResultData.add(exam);
        int index = mOriginalData.indexOf(exam);
        notifyItemInserted(index);
    }

    public void removeItem(int index) {
        mOriginalData.remove(index);
        notifyItemRemoved(index);
    }

    public void removeItem(Skills exam) {
        int index = mOriginalData.indexOf(exam);
        mOriginalData.remove(exam);
        notifyItemRemoved(index);
    }

    public Filter getFilter() {
        return mFilter;
    }


    public Skills getItem(int index) {
        return mOriginalData.get(index);
    }

    public void replaceItem(int index, Skills audioMeta) {
        mOriginalData.set(index, audioMeta);
        notifyItemChanged(index);
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        CheckBox checkSkill;

        public ViewHolder(View itemView) {
            super(itemView);

            checkSkill = (CheckBox) itemView.findViewById(R.id.chkSkill);
            checkSkill.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onRecyclerViewClick.onItemClick(v, getLayoutPosition());
                }
            });
        }
    }


    private class ItemFilter extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {

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

            FilterResults results = new FilterResults();

            int count = mOriginalData.size();

            final ArrayList<Skills> tempFilterList = new ArrayList<Skills>(count);

            String filterableString;

            for (int i = 0; i < count; i++) {
                filterableString = mOriginalData.get(i).getSkill();
                if (filterableString.toLowerCase().contains(filterString)) {
                    tempFilterList.add(mOriginalData.get(i));
                }
            }

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

            return results;
        }

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

В работе Используйте

    mAdapter = new SkillAdapter(SkillsActivity.this, SkillsActivity.this);
    recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
    recyclerView.setAdapter(mAdapter);

Затем Filter

editSearch.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            mAdapter.getFilter().filter(editSearch.getText().toString());
        }
    });