Tuesday, April 7, 2020

Custom RecyclerView adapter with multiple view items example

RecyclerView in Android has been the defacto for viewing lists in android. The solid performance and the ability to plugin any feature into a list without breaking a sweat made it the developer favorite. Ultimately replacing Listviews from being the standard way of displaying lists in android applications. What makes the RecyclerView the go-to library when thinking about lists?

How does a RecyclerView work?

Having a deeper understanding of the Custom RecyclerView example and the RecyclerViewAdapter will help a lot in writing efficient code. Let’s see what makes RecyclerView awesome. At the core, the view is known for it’s recycling ability of child views that help reduce memory usage (That’s where the name comes from). At first, RecyclerView initializes a set of child views to display a certain amount of contents in the list to fill the viewport of the screen. Once the user starts scrolling, the view which gets past the screen boundary is used to repopulate and reused at the other end, this is done by the Adapter.
Custom RecyclerView adapter with multiple view items example

Custom RecyclerView Adapter

Before attaching a Custom Adapter to the RecyclerView, make sure you have included the RecyclerView view tags in the layout (xml) file.
<RecyclerView
    android:id="@+id/recycler_view"
    android:scrollbars="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
 Create a new XML layout file in res/layout/ with your desired layout design.
 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_parent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="5dp">
    <TextView
        android:id="@+id/txt_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:padding="5dp"/>
    <TextView
        android:id="@+id/txt_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="15sp"
        android:padding="5dp"/>
</LinearLayout>
 Create a Java Class to hold the necessary information regarding the data objects.
 public class Contact {
    private String name;
    private String number;
    public Contact(String name, String number) {
        this.name = name;
        this.number = number;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
}
Now Let’s start working on the custom Adapter for the RecyclerView. Create a new Java Class extending the RecyclerView.Adapter and override the following methods from the parent class.
We also need to create a nested sub-class extending the RecyclerView.ViewHolder which helps to create ViewHolders which populates data to the views present in the recyclerView. Once we wire up everything, our Custom adapter will look something similar to this.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ContactHolder> {
    // List to store all the contact details
    private ArrayList<Contact> contactsList;
    private Context mContext;
    // Counstructor for the Class
    public VideoListAdapter(ArrayList<Contact> contactsList, Context context) {
        this.contactsList = contactsList;
        this.mContext = context;
    }
    // This method creates views for the RecyclerView by inflating the layout
    // Into the viewHolders which helps to display the items in the RecyclerView
    @Override
    public ContactHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        // Inflate the layout view you have created for the list rows here
        View view = layoutInflater.inflate(R.layout.contact_list_item, parent, false);
        return new ContactHolder(view);
    }
    @Override
    public int getItemCount() {
        return contactList == null? 0: contactList.size();
    }
    // This method is called when binding the data to the views being created in RecyclerView
    @Override
    public void onBindViewHolder(@NonNull ContactHolder holder, final int position) {
        final Contact contact = contactList.get(position);
     
        // Set the data to the views here
        holder.setContactName(contact.getName());
        holder.setContactNumber(contact.getNumber());
       // You can set click listners to indvidual items in the viewholder here
       // make sure you pass down the listner or make the Data members of the viewHolder public
 
    }
    // This is your ViewHolder class that helps to populate data to the view
    public class ContactHolder extends RecyclerView.ViewHolder {
        private TextView txtName;
        private TextView txtNumber;
     
        public ContactHolder(View itemView) {
            super(itemView);
            txtName = itemView.findViewById(R.id.txt_name);
            txtNumber = itemView.findViewById(R.id.txt_number);
        }

        public void setContactName(String name) {
            txtName.setText(name);
        }
        public void setContactNumber(String number) {
            txtNumber.setText(number);
        }
    }
}
You can either hardcode the values of the contact or asynchronously load the data into the list and pass it down to the adapter to do the job of displaying it in the RecyclerView.
public class MainActivity extends AppCompatActivity {
    private MyAdapter listAdapter;
    private ArrayList<Contact> contactsList = new ArrayList<>();
    private RecyclerView recycler;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recycler = findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recycler.setLayoutManager(layoutManager);
        listAdapter = new MyAdapter(contactsList, this);
        recycler.setAdapter(listAdapter);
     
        //Load the date from the network or other resources
        //into the array list asynchronously
     
        contactsList.add(new Contact("Daniel Shiffman", "778899009"));
        contactsList.add(new Contact("Jhon Doe", "778899009"));
        contactsList.add(new Contact("Jane Doe", "778899009"));
     
        listAdapter.notifyDataSetChanged();
    }
}

Custom Recycler Adapter for Multiple Views

public class Contact {
    //Add the type indicators here
    public static final int TEXT_TYPE = 0;
    public static final int IMAGE_TYPE = 0;
    private int viewType;
    private String name;
    private String number;
    public Contact(int viewType,String name, String number) {
        this.viewType = viewType;
        this.name = name;
        this.number = number;
    }
 
    public int getViewType() {
       return viewType;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
}
Note that we are using a unique integer to note the type of view the object requires in the RecyclerView. This indicator can be used in the RecyclerView Adapter to use a specific layout with the ViewHolder. Here the Notable parts are the ViewType indicator variables in the data class (model class), the overding of <code>getItemViewType()</code> method and switching the layouts based on this on the onCreateViewHoder method.
public class MyAdapter extends RecyclerView.Adapter<RecylerView.ViewHolder> {
    // List to store all the contact details
    private ArrayList<Contact> contactsList;
    private Context mContext;
    // Counstructor for the Class
    public VideoListAdapter(ArrayList<Contact> contactsList, Context context) {
        this.contactsList = contactsList;
        this.mContext = context;
    }
    // This method creates views for the RecyclerView by inflating the layout
    // Into the viewHolders which helps to display the items in the RecyclerView
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        // Inflate the layout view you have created for the list rows here
        // use the viewType to inflate specic Layouts for the ViewHolders
     
        switch(viewType) {
             case Contact.TEXT_TYPE:
                   // Inflate the first view type
                   View view = layoutInflater.inflate(R.layout.list_layout_1, parent, false);
                   return new ViewHolder1(view);
             case Contact.TEXT_TYPE:
                   // inflate the second view type
                   View view = layoutInflater.inflate(R.layout.list_layout_2, parent, false);
                   return new ViewHolder2(view);
        }
        // always use a fallback ViewHolder
        View view = layoutInflater.inflate(R.layout.default_list_layout, parent, false);
        return new ViewHolder(view);
    }
    @Override
    public int getItemCount() {
        return contactList == null? 0: contactList.size();
    }
    @Override
    public int getItemViewType(int position) {
        int type = contactsList.get(position).getViewType();
        return type;
    }
    // This method is called when binding the data to the views being created in RecyclerView
    @Override
    public void onBindViewHolder(@NonNull ContactHolder holder, final int position) {
        final Contact contact = contactList.get(position);
     
        // Set the data to the views here
        holder.setContactName(contact.getName());
        holder.setContactNumber(contact.getNumber());
       // You can set click listners to indvidual items in the viewholder here
       // make sure you pass down the listner or make the Data members of the viewHolder public
 
    }
    // This is your ViewHolder class that helps to populate data to the view
    public class viewHolder1 extends RecyclerView.ViewHolder {
       // Your First view holder
       // Connect with the items in the layout here
    }
 
   public class viewHolder2 extends RecyclerView.ViewHolder {
       // Your Second view holder
       // Connect with the items in the layout here
    }
}

No comments:

Post a Comment