Android: how to switch layouts for a RecyclerView list?

I have a default layout that contains a bunch of blank cards in the RecyclerView list, basically a welcome screen for the user to show them how the cards look. The user then launches the input screen for some data and clicks the "Save" button to save the data in CardView. As soon as the user clicks the “Save” button, the layout should change from the default layout with empty CardViews to a new single CardView that contains user data. Later, if the user deletes all his cards, then the view should return to empty Card views by default.

I am trying to set the int Adapter code to onCreateViewHolder because getItemCount () will already have a positive value for the default value (since the RecyclerView list will already contain 4 or 5 empty cards) that conflict later with the same amount getItemCount (), as only user will create 4 or 5 cards. Any ideas on how to set the default layout and then switch to a new layout, which can then revert to the default layout if the list is empty from the user-created CardViews?

Below is my unsuccessful attempt to test for two layouts in the adapter. I realized that this would not work, because the default layout never had an ItemCount with a zero value, since there are already 4 or 5 empty CardViews:

... public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> { private List<ContactInfo> contactList; public ContactAdapter(List<ContactInfo> contactList) { this.contactList = contactList; } @Override public int getItemCount() { return contactList.size(); } @Override public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { if(contactList.size()== 0) { View itemView = LayoutInflater. from(viewGroup.getContext()). inflate(R.layout.defaultcard_layout, viewGroup, false); return new ContactViewHolder(itemView); } else { View itemView = LayoutInflater. from(viewGroup.getContext()). inflate(R.layout.singlecard_layout, viewGroup, false); return new ContactViewHolder(itemView); } } 

adapter code and removeItem changed:

 ... private LayoutInflater mLayoutInflater; private List<Contact> mContacts; private OnItemTapListener mOnItemTapListener; public ListContactsAdapter(Context context, List<Contact> contacts) { Context mContext; mContext = context; mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mContacts = contacts; } public void removeItem(Contact contact, int position) { mContacts.remove(contact); if (mContacts.size()==0) { // if no more contacts in list, // we rebuild from scratch mContacts.clear(); notifyDataSetChanged(); } else { // else we just need to remove // one item mContacts.remove(position); notifyItemRemoved(position); } } 
+1
source share
1 answer

This is an approach you could follow:

  • Define a highlighted abstract type for list items (such as ListItem) to wrap your business objects. Its implementation may be something like this:

     public abstract class ListItem { public static final int TYPE_EMPTY = 0; public static final int TYPE_CONTACT = 1; abstract public int getType(); } 
  • Define a class for each type of your list item:

     public class EmptyItem { @Override public int getType() { return TYPE_EMPTY; } } public class ContactItem { private ContactInfo contact; // here getters and setters // for title and so on, built // using contact public ContactItem(ContactInfo info) { this.contact = info; } @Override public int getType() { return TYPE_CONTACT; } } 
  • Create your list. In the logic below, I simply guarantee that you will always have at least 5 elements. If you have less than 5 contacts, an empty layout will be displayed. Each time you change your contact list from an external activity, such a modification will be available even in mContactList, because the adapter maintains a link to the same list managed in Activity (see Adapter Constructor). For example, if you add a new contact, you just need to call the updateContactList method to update your interface.

     List<ContactInfo> mContactList; List<ListItem> mItems; public ContactsAdapter(List<ContactInfo> contactList) { mContactList = contactList; mItems = buildContactsList(mContactList); } // Method for building ui list. private List<ContactItem> buildContactsList(List<ContactInfo> contactList) { List<ContactItem> list = new ArrayList<>(); for (ContactInfo contact : contactList) { list.add(ContactItem(contact)); } if (list.size() < 5) { for (int i=list.size(); i<5; i++) { list.add(EmptyItem()); } } } // Method for updating contact list, providing // a new one. Everything to be build from scratch. public void updateContactsList() { mItems.clear(); mItems.addAll(buildContactsList(mContactList)); notifyDataSetChanged(); } 
  • Define an adapter for your RecyclerView, working on the list defined at point 3. Here it is important to override the getItemViewType method as follows:

     @Override public int getItemViewType(int position) { return mItems.get(position).getType(); } 

    Then you need to have two layouts and a ViewHolder for the blank and contact elements. Adapters should take care of this as follows:

     @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == ListItem.TYPE_EMPTY) { View itemView = mLayoutInflater.inflate(R.layout.defaultcard_layout, parent, false); return new EmptyViewHolder(itemView); } else { View itemView = mLayoutInflater.inflate(R.layout.singlecard_layout, parent, false); return new ContactViewHolder(itemView); } } @Override public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) { int type = getItemViewType(position); if (type == ListItem.TYPE_EMPTY) { EmptyItem header = (EmptyItem) mItems.get(position); EmptyViewHolder holder = (EmptyViewHolder) viewHolder; // your logic here... probably nothing to do since it empty } else { ContactItem event = (ContactItem) mItems.get(position); ContactViewHolder holder = (ContactViewHolder) viewHolder; // your logic here } } 

In the case of updates to contactList you should, of course, update mItems by clearing it, filling it again with the same logic that is reported in step 3, and then notifying the DataSetChanged on the adapter.

+2
source

Source: https://habr.com/ru/post/1242275/


All Articles