How to make a horizontal layout list with Recyclerview
Tags: android, java, beginners
Published: 2021-05-15 03:21:47

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](https://dev.to/tomokawaguchi/utilising-listview-and-arrayadapter-in-java-20i0). 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 `LayoutManager`s, 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 `TextView`s and 1 `ImageView`)
3. Create a custom `RecyclerView` and `ViewHolder` to showcase list items
4. Set up the custom `RecyclerView` with a `LayoutManager` and adapter

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/letiaiqkb88cnao9daul.png)

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

```java
// 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;
    }
}
```
Once we have the data model class, let's populate our `ArrayList` to contain subjects details. 

```java
// 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

```
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.

```xml
// 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>
```
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. 

```java
// 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);
        }
    }
}


```
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()`.

```java
// 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();
    }
}
```
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 the`LayoutManager` 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`.

```java
// 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));

```
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 😄