Home Listview to recyclerview: how do I implement 2 possible viewholders?
Reply: 2

Listview to recyclerview: how do I implement 2 possible viewholders?

CHarris
1#
CHarris Published in 2018-01-12 23:05:32Z

In my Listview this code works:

    for (int number = 0; number < matchingContacts.size(); number++) {

        //if a phone number is in our array of matching contacts
        if (matchingContacts.contains(selectPhoneContact.getPhone()))

        {
            //if a matching contact, no need to show the Invite button
            viewHolder.invite.setVisibility(View.GONE);

            //once a matching contact is found, no need to keep looping x number of time, move onto next contact
            break;

        } else {
            //if not a matching contact, no need to show the check box
            viewHolder.check.setVisibility(View.GONE);

        }

    }

If a phone number is in the matching arraylist then it should make the invite button invisible, if it is not in the matching arraylist it should make the checkbox invisible.

But not in my recyclerview, in which I am trying to make the code work.

On first load it looks ok but as soon as you start to scroll the views get messed up - checkboxes and buttons appear where they are not supposed to.

I've read that in Recyclerview you are supposed to implement this with case statements, and I've looked here Why RecyclerView items disappear with scrolling and here How to create RecyclerView with multiple view type? but for the life of me I cannot get it to work!

Can you help?

Here is my code:

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

    //make a List containing info about SelectPhoneContact objects
    public List<SelectPhoneContact> theContactsList;

    Context context_type;

    ArrayList<String> matchingContacts = new ArrayList<String>();

    public static class ViewHolder extends RecyclerView.ViewHolder {

        //In each recycler_blueprint show the items you want to have appearing
        public TextView title, phone;
        public CheckBox check;
        public Button invite;


        public ViewHolder(final View itemView) {
            super(itemView);
            //title is cast to the name id, in recycler_blueprint,
            //phone is cast to the id called no etc
            title = (TextView) itemView.findViewById(R.id.name);
            phone = (TextView) itemView.findViewById(R.id.no);
            invite = (Button) itemView.findViewById(R.id.btnInvite);
            check = (CheckBox) itemView.findViewById(R.id.checkBoxContact);

        }

    }

    public PopulistoContactsAdapter(List<SelectPhoneContact> selectPhoneContacts, Context context, int activity) {

        theContactsList = selectPhoneContacts;
        context_type = context;

        matchingContacts.add("+3531234567");
        matchingContacts.add("+3536789012");
        matchingContacts.add("+3530987654");
        matchingContacts.add("+3538765432");

    }

    @Override
    public PopulistoContactsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);
        View contactView = inflater.inflate(R.layout.recycler_blueprint, parent, false);
        ViewHolder viewHolder = new ViewHolder(contactView);

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(final PopulistoContactsAdapter.ViewHolder viewHolder, final int position) {
        //bind the views into the ViewHolder
        //selectPhoneContact is an instance of the SelectPhoneContact class.
        //We will assign each row of the recyclerview to contain details of selectPhoneContact:

        //The number of rows will match the number of contacts in our contacts list
        final SelectPhoneContact selectPhoneContact = theContactsList.get(position);

        //a text view for the name, set it to the matching selectPhoneContact
        TextView title = viewHolder.title;
        title.setText(selectPhoneContact.getName());

        //a text view for the number, set it to the matching selectPhoneContact
        TextView phone = viewHolder.phone;
        phone.setText(selectPhoneContact.getPhone());

        Button invite = viewHolder.invite;

        CheckBox check = viewHolder.check;

        for (int number = 0; number < matchingContacts.size(); number++) {

            //if a phone number is in our array of matching contacts
            if (matchingContacts.contains(selectPhoneContact.getPhone()))

            {
                //if a matching contact, no need to show the Invite button
                viewHolder.invite.setVisibility(View.GONE);
                //once a matching contact is found, no need to keep looping x number of time, move onto next contact
                break;

            } else {
                //if not a matching contact, no need to show the check box
                viewHolder.check.setVisibility(View.GONE);

            }

        }

    }

    @Override
    public int getItemCount() {

        return theContactsList.size();
    }
}
Alex Kamenkov
2#
Alex Kamenkov Reply to 2018-01-13 00:18:41Z

RecyclerView can handle multiple view types with different view holders.

First of all you have to override the getItemViewType(int position) method on your adapter which will return type of the object according its position. Then create view holder class for each view type.

Handle onCreateViewHolder(ViewGroup parent, int viewType) method considering the view type:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == YOUR_FIRST_TYPE) {
        //inflate first type of view
        return new FirstTypeViewHolder(view);
    } else if (viewType == YOUR_SECOND_TYPE) {
        //inflate second type of view
        return new SecondTypeViewHolder(view);
    }
}

Handle onBindViewHolder(ViewHolder viewHolder, int position) considering the view type:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
    int viewType = getItemViewType(position);

    if (viewType == YOUR_FIRST_TYPE) {
        FirstTypeViewHolder firstTypeViewHolder = (FirstTypeViewHolder) viewHolder;
        //do your stuff
    } else if (viewType == YOUR_SECOND_TYPE) {
        SecondTypeViewHolder secondTypeViewHolder = (SecondTypeViewHolder) viewHolder;
        //do your stuff
    }
}

You can take a look on this tutorial.

Brian
3#
Brian Reply to 2018-01-12 23:28:03Z

Method 1: Actually in you case, using multiple View types is not necessary. This might be an easier way. Instead, I would recommend you amend your SelectPhoneContact class to include a simple boolean field (maybe called isMatching) that flags whether or not this phone number is a matching contact. You can then create a simple setter and getter methods like setIsMatchingContact(boolean) and isMatchingContact() to update/read this flag.

When you're initializing the list and adding the SelectPhoneContact, do the pre-processing of determining which instances belong or don't belong in the matching contacts by setting the setIsMatchingContact(boolean) method. In your onBindViewHolder method, rather than iterating over matchingContacts, you just check selectPhoneContact.isMatchingContact() and change the visibility accordingly. This is also more efficient as you don't have to perform a potentially expensive operation of iterating through a large list in a bind method which could cause the scrolling to stutter and have issues.

If your matchingContacts list changes throughout time, you could always write a method that iterates through the SelectPhoneContact list and resets the isMatching boolean.

Method 2: If you rather not extend the your SelectPhoneContact class to have those two methods I mentioned, you could alternatively create a private static wrapper class like this:

private static class SelectPhoneContactItem {
    SelectPhoneContact selectPhoneContact;
    boolean isMatching;
}

Then use this as the primary list in your adapter:

public List<SelectPhoneContactItem> theContactsList;

Like Method 1, you should the pre-processing of the figuring out which SelectPhoneContactItem is in the matchingContacts and assign the isMatching boolean as needed.

You should probably go with Method 1 unless there are some design constraints. Let me know if my answer makes sense, hope this helps!

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.353398 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO