Search code examples
androidcheckboxfilterandroid-recyclerviewsearchview

Filterable recyclerview with checkboxes


Goal: keep track of selected items of a recyclerview using a changing Imageview for each row. Pratically i'm implementing a sort of checkbox.

Checking works fine:

enter image description here

but when I try to search for some items, checked items change: only first item of my list is checked:

enter image description here

I'll post my code below:

Shop Selected Interface

public interface NearestShopActivityAdapterListener {
    void onShopSelected(FShop shop, View view);
}

My View Holder

public class MyHolder extends RecyclerView.ViewHolder{
    public TextView name, address;
    public ImageView logo;

    public MyHolder(View itemView) {
        super(itemView);
        name = (TextView) itemView.findViewById(R.id.activityNearestShopListItemUhop);
        address = (TextView) itemView.findViewById(R.id.activityNearestShopListItemAddress);
        logo = (ImageView) itemView.findViewById(R.id.activityNearestShopListItemImage);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                listener.onShopSelected(filteredShopList.get(getAdapterPosition()),view);
            }
        });
    }

onShopSelected function

 @Override
public void onShopSelected(FShop shop, View view) {
    if(checkList.contains(shop.getShopId())){
        mImgViewCheckBox = (ImageView) view.findViewById(R.id.checkBoxNearestShop);
        mImgViewCheckBox.setImageResource(R.drawable.checkbox_selector_not_checked);
        checkList.remove(shop.getShopId());
    }else {
        mImgViewCheckBox = (ImageView) view.findViewById(R.id.checkBoxNearestShop);
        mImgViewCheckBox.setImageResource(R.drawable.ic_checked);
        checkList.add(shop.getShopId());
    }
}

Where I am wrong? I would try to associate the ImageView mImgViewCheckBox with the Shop id and not with its position in the recyclerview, but I have no idea on how to do it. Thnak you in advance.


Solution

  • i have done this things in contact details. i provide my adapter and method you can change code your according needs .

    InviteContactAdapter.java

    public class InviteContactAdapter extends RecyclerView.Adapter<InviteContactAdapter.ItemViewHolder> implements Filterable {
    private List<UserContact> mContactList = new ArrayList<>();
    private List<UserContact> mContectFilter = new ArrayList<>();
    private Context mContext;
    private CustomFilter mFilter;
    public List<String> mEmailList = new ArrayList<>();
    
    public InviteContactAdapter(Context context, List<UserContact> mContactList) {
        mContext = context;
        this.mContactList = mContactList;
        this.mContectFilter = mContactList;
        mFilter = new CustomFilter();
    }
    
    public onItemClickListener onItemClickListener;
    
    public void setOnItemClickListener(InviteContactAdapter.onItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }
    
    @Override
    public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.invite_contact_row_layout, viewGroup, false);
        return new ItemViewHolder(view);
    }
    
    public interface onItemClickListener {
        void onClick(UserContact contact);
    }
    
    @Override
    public Filter getFilter() {
        return mFilter;
    }
    
    @Override
    public void onBindViewHolder(final ItemViewHolder itemViewHolder, int i) {
        final UserContact contact = mContectFilter.get(i);
        itemViewHolder.mTvUserNane.setText(contact.getUserName().trim());
        itemViewHolder.mTvUserEmail.setText(contact.getUserEmail().trim());
        if (contact.isSelect())
            itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
        else
            itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
    
    
        itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
    
                if (contact.isSelect()) {
                    contact.setSelect(false);
                    itemViewHolder.mIvSelect.setImageResource(R.drawable.un_check_contact);
                } else {
                    contact.setSelect(true);
                    itemViewHolder.mIvSelect.setImageResource(R.drawable.check_contect);
                }
            }
        });
    
    }
    
    @Override
    public int getItemCount() {
        return mContectFilter.size();
    }
    
    public class ItemViewHolder extends RecyclerView.ViewHolder {
        private TextView mTvUserNane, mTvUserEmail;
        private ImageView mIvSelect;
    
        public ItemViewHolder(View itemView) {
            super(itemView);
            mTvUserEmail = itemView.findViewById(R.id.icrlTvUserEmail);
            mTvUserNane = itemView.findViewById(R.id.icrlTvUserName);
            mIvSelect = itemView.findViewById(R.id.icrlIvSelect);
        }
    }
    
    public List<String> getEmail() {
        mEmailList.clear();
        for (UserContact contact : mContectFilter) {
            if (contact.isSelect()) {
                mEmailList.add(contact.getUserEmail());
            }
        }
        return mEmailList;
    }
    
    /**
     * this class for filter data.
     */
    class CustomFilter extends Filter {
    
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            FilterResults results = new FilterResults();
            if (charSequence != null && charSequence.length() > 0) {
                ArrayList<UserContact> filters = new ArrayList<>();
                charSequence = charSequence.toString().toUpperCase();
                for (int i = 0; i < mContactList.size(); i++) {
                    if (mContactList.get(i).getUserName().toUpperCase().contains(charSequence) || mContactList.get(i).getUserEmail().toUpperCase().contains(charSequence)) {
                        UserContact contact = new UserContact();
                        contact.setUserName(mContactList.get(i).getUserName());
                        contact.setUserEmail(mContactList.get(i).getUserEmail());
                        filters.add(contact);
    
                    }
                }
                results.count = filters.size();
                results.values = filters;
    
            } else {
                results.count = mContactList.size();
                results.values = mContactList;
            }
            return results;
        }
    
        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            mContectFilter = (ArrayList<UserContact>) filterResults.values;
            notifyDataSetChanged();
        }
    }
    

    }

    then after bind contact data into recycler view and search data based on name and email.. make set adapter method ..

      private void setAdapter(){
        if (!mContactList.isEmpty()) {
            inviteContactAdapter = new InviteContactAdapter(getActivity(), mContactList);
            mRvData.setAdapter(inviteContactAdapter);
            inviteContactAdapter.setOnItemClickListener(new InviteContactAdapter.onItemClickListener() {
                @Override
                public void onClick(UserContact contact) {
                    mEmailList.add(contact.getUserEmail());
                }
            });
        } else {
            mTvEmpty.setVisibility(View.VISIBLE);
        }
    }
    

    then after make search data method ...

       /**
     * this method sort data.
     */
    private void sortData(View root) {
        mEtSearchData = (EditText) root.findViewById(R.id.icffEtSearch);
        mEtSearchData.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) {
                if (inviteContactAdapter != null) {
                    inviteContactAdapter.getFilter().filter(s);
                }
            }
    
            @Override
            public void afterTextChanged(Editable s) {
            }
        });
    
    }
    

    after getting contact data it will be work. and you can change code your according.