DEV Community

Cover image for How to make a horizontal layout list with Recyclerview
Tomo
Tomo

Posted on • Updated on

How to make a horizontal layout list with Recyclerview

You often encounter situations where you need to handle lists of items in mobile app development. One of the approaches you could go with is utilising ListView and ArrayAdapter(if your data is stored in an ArrayList) as I explained in my previous article. This is not a bad approach but it turns out it only caters for a vertical layout.
As I was looking for a way to display my list items horizontally and scrollable, utilizing Recyclerview appears to be one of the best approaches.

What is RecyclerView?

If you are familiar with ListView, RecyclerView is an improved version of it. It allows us to implement the layout more flexibly as well as to handle a larger amount of data even more efficiently. To understand RecyclerView better, let's look at some of the features and requirements when you use RecyclerView.

In order to utilise RecyclerView, you need to work with RecyclerView.Adapter, ViewHolder and LayoutManager. RecyclerView.Adapter is an adapter that populates the child items of the RecyclerView just like ArrayAdapter. However, it requires ViewHolder which acts as a kind of template of the child item (ViewHolder pattern). ViewHolder is handy for the adapter as it contains the details of views within a row. Furthermore, by defining this ViewHolder pattern first, it eliminates the repetitive use of the findViewById() method. This saves us a lot from slowing down the app performance while scrolling the items. When we utilise ArrayAdapter, the process of recycling view was good but we still need to call the findViewById() method multiple times to look up the elements to update the view data. Compare to this, using the ViewHolder approach is definitely more efficient.

Now let's talk about another key player for this topic, LayoutManager. As mentioned above, one of the benefits of using RecyclerView is horizontal list layout and this is thanks to LayoutManager. LayoutManager is basically in charge of positioning child items as well as for deciding when to reuse old views. RecyclerView offers flexible layouts and there are 3 different LayoutManagers, which are:

  • LinearLayoutManager : displaying items vertically or horizontally
  • GridLayoutManager : displaying items in a grid vertically or horizontally
  • StaggeredGridLayoutManager : displaying items in a staggered grid (different width/height are allowed)

By utilising these mentioned key players together, RecyclerView can successfully create child items in an efficient way. Now let's look at a detailed example of how to use RecyclerView.

How to use RecyclerView

In this article, we assume that we want to showcase a list of subjects in a horizontal layout. Each item includes the name of the subject, image and the number of likes. First, let's start with considering the high-level view of what we need to do:

  1. Define a model class called Subject to store all of your field types (subject name, image and number of likes)
  2. Populate your subject's data and store it in an ArrayList
  3. Define the layout of each list item (2 TextViews and 1 ImageView)
  4. Create a custom RecyclerView and ViewHolder to showcase list items
  5. Set up the custom RecyclerView with a LayoutManager and adapter

Alt Text

Let's tackle one by one. We first need to define a class called Subject to store required fields and set up getter methods.

// Subject.java

public class Subject {
    private String subject;
    private int imageId;
    private int numOfLikes;

    // Constructor
    public Subject(String subject, int imageId, int numOfLikes){
        this.subject = subject;
        this.imageId = imageId;
        this.numOfLikes = numOfLikes;
    }

    //Setting up the getter methods
    public String getSubject() {
        return subject;
    }

    public int getImageId() {
        return imageId;
    }

    public int getNumOfLikes() {
        return numOfLikes;
    }
}
Enter fullscreen mode Exit fullscreen mode

Once we have the data model class, let's populate our ArrayList to contain subjects details.

// MainActivity.java

ArrayList<Subject> subjectArrayList = new ArrayList<>();
subjectArrayList.add(new Subject("English", R.drawable.english, 27));
subjectArrayList.add(new Subject("Math", R.drawable.math, 13));
subjectArrayList.add(new Subject("P.E", R.drawable.pe, 45));
subjectArrayList.add(new Subject("Science", R.drawable.science, 41));
subjectArrayList.add(new Subject("Art", R.drawable.art, 36));
....etc

Enter fullscreen mode Exit fullscreen mode

Next, we will quickly set up the layout of the individual item. As mentioned, we will have 2 TextViews and 1 ImageView for the example in this article. Just a side note that if you want your layout to be VERTICAL, be careful with the height of the row (root view of the list) as it needs to be wrap_content to show your items correctly.

// list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content" 
    android:layout_margin="16dp"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/subject_image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/subject_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />

    <TextView
        android:id="@+id/likes_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />

</LinearLayout>
Enter fullscreen mode Exit fullscreen mode

Now we will move on to our custom SubjectAdapter that extends the RecyclerView.Adapter. Please note here that we need to define a custom ViewHolder to specify and give access to all of the Views. This is because we will use this custom ViewHolder later to bind the data. It also prevents us from calling findById() methods multiple times when the adapter assigns data to respective views.

// SubjectAdapter.java

public class SubjectAdapter extends RecyclerView.Adapter<SubjectAdapter.ViewHolder> {
    // This is a template - give a direct reference to each view
    public class ViewHolder extends RecyclerView.ViewHolder{
        public ImageView subjectImageView;
        public TextView subjectTextView;
        public TextView numOfLikesTextView;

        // Constructor - accepts entire row item
        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            // Find each view by id you set up in the list_item.xml
            subjectImageView = itemView.findViewById(R.id.subject_image_view);
            subjectTextView = itemView.findViewById(R.id.subject_text_view);
            numOfLikesTextView = itemView.findViewById(R.id.likes_text_view);
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

After setting up ViewHolder, let's start working on the adapter now. There are 4 major things to do here: setting up a constructor and overriding 3 different methods, which are onCreateViewHolder(), onBindViewHolder() and getItemCount().

// SubjectAdapter.java

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

    // ... ViewHolder class and its constructor as per above


    ArrayList<Subject> list;

    // Constructor
    public SubjectAdapter(ArrayList<Subject> list){
        this.list = list;
    }

    // Creating a viewHolder
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // Inflate the layout
        View contactView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item, parent, false);

        // Return a new holder instance
        ViewHolder viewHolder = new ViewHolder(contactView);

        return viewHolder;
    }

    // Assigning respective data for the views based on the position of the current item
    @Override
    public void onBindViewHolder(@NonNull SubjectAdapter.ViewHolder holder, int position) {
        // Get the Subject based on the current position
        Subject currentItem = list.get(position);

        // Setting views with the corresponding data
        ImageView imageView = holder.subjectImageView;
        imageView.setImageResource(currentItem.getImageId());

        TextView subjectTextView = holder.subjectTextView;
        subjectTextView.setText(currentItem.getSubject());

        TextView likesTextView = holder.numOfLikesTextView;
        likesTextView.setText(currentItem.getSubject());
    }

    // Indicating how long your data is
    @Override
    public int getItemCount() {
        return list.size();
    }
}
Enter fullscreen mode Exit fullscreen mode

Here we start off by setting up a constructor for the adapter. Simply passing the list of data so that our adapter can utilise it to populate items. Next, let's look at the onCreateViewHolder() method. This method is called by theLayoutManager and it handles layout inflation when needed. Returning the ViewHolder with all of the necessary details is its role as well. Moving onto the next, the onBindViewHolder() method plays a critical role to bind data to corresponding views. By utilising the predefined view details from the ViewHolder, it manages to replace the content efficiently. Finally getItemCount() method is a way to inform the adapter about the size of your data, which is the total number of items to showcase.

After going through the above process, all you need to do is to set up Recyclerview with your custom adapter and LayoutManager.

// MainActivity.java

// Find RecyclerView by Id (from the activity_main.xml)
RecyclerView recyclerView = findViewById(R.id.recycler_view);
// Instantiate SubjectAdapter with the data
SubjectAdapter adapter = new SubjectAdapter(subjectsList);
// Set adapter with RecyclerView
recyclerView.setAdapter(adapter);
// Set LayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));

Enter fullscreen mode Exit fullscreen mode

One thing to note here is that we chose to implement LinearLayoutManage with a horizontal layout this time. Luckily it sets to be scrollable automatically if there are many items. But if you wish to implement other styles, you could do so here by instantiating different LayoutManager with your chosen dimension.

Summary

We have gone through how to utilise RecyclerView with custom RecyclerView.Adapter and LayoutManager. This is one of the best approaches to efficiently display a list of items. I found it quite useful and it has actually more to offer such as item animation. (I will write about this when I know it better!)

Please feel free to leave a comment and your inputs are more than welcome and appreciated! Thanks for reading 😄

Top comments (0)