Android Recyclerview Horizontal Scroll Example

This example will show you how to add and update RecyclerView items when horizontal scroll it. When the user scrolls from left to right at the beginning of RecyclerView, it will add a new item at the beginning. When the user scrolls from right to left at the end of RecyclerView, it will insert another new item at the ending.

If you can not watch the above video, you can see it on the youtube URL https://youtu.be/zPSxzVdjE6Y

  1. First, you should add below dependency library in the project build.gradle file dependencies section.
    compile 'com.android.support:cardview-v7:26.+'
    compile 'com.android.support:recyclerview-v7:26.+'
    

1. Example Java File Structure.

  1. There are 4 java files, 1 activity layout XML file, and 1 RecyclerView item layout XML file as below.
    ./
    ├── app
    │   ├── build.gradle
    │   ├── proguard-rules.pro
    │   └── src
    │       ├── main
    │       │   ├── AndroidManifest.xml
    │       │   ├── java
    │       │   │   └── com
    │       │   │       └── dev2qa
    │       │   │           └── example
    │       │   │               ├── view
    │       │   │               │   ├── recycler_view
    │       │   │               │   │   ├── CustomRecyclerViewDataAdapter.java
    │       │   │               │   │   ├── CustomRecyclerViewHolder.java
    │       │   │               │   │   ├── CustomRecyclerViewItem.java
    │       │   │               │   │   └── CustomRecyclerViewScrollActivity.java

2. Main Activity.

  1. CustomRecyclerViewScrollActivity.java
    package com.dev2qa.example.view.recycler_view;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.util.Log;
    import android.view.View;
    import android.widget.ProgressBar;
    import android.widget.Toast;
    
    import com.dev2qa.example.R;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class CustomRecyclerViewScrollActivity extends AppCompatActivity {
    
        private static final String LOG_TAG = CustomRecyclerViewScrollActivity.class.getSimpleName();
    
        private RecyclerView recyclerView = null;
    
        private List<CustomRecyclerViewItem> itemList = null;
    
        private CustomRecyclerViewDataAdapter customRecyclerViewDataAdapter = null;
    
        private ProgressBar progressBar = null;
    
        // This handler is used to update activity UI components/
        private Handler uiHandler = null;
    
        private int MESSAGE_UPDATE_RECYCLER_VIEW = 1;
    
        private String MESSAGE_KEY_NEW_ITEM_INDEX = "MESSAGE_KEY_NEW_ITEM_INDEX";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_custom_refresh_recycler_view);
    
            setTitle("dev2qa.com - Android RecyclerView Horizontal Scroll Example.");
    
            initControls();
    
            // Create the recycler view object.
            RecyclerView recyclerView = (RecyclerView)findViewById(R.id.custom_refresh_recycler_view);
            // Create the grid layout manager with 2 columns.
            GridLayoutManager layoutManager = new GridLayoutManager(this,1);
            layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
            //layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    
            // Set layout manager.
            recyclerView.setLayoutManager(layoutManager);
    
            // Create car recycler view data adapter with car item list.
            customRecyclerViewDataAdapter = new CustomRecyclerViewDataAdapter(itemList);
            // Set data adapter.
            recyclerView.setAdapter(customRecyclerViewDataAdapter);
    
            // Scroll RecyclerView a little to make later scroll take effect.
            recyclerView.scrollToPosition(1);
        }
    
        private void initControls()
        {
            if(recyclerView == null)
            {
                recyclerView = (RecyclerView)findViewById(R.id.custom_refresh_recycler_view);
    
                recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
    
                        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
    
                        int firstCompleteVisibleItemPosition = -1;
                        int lastCompleteVisibleItemPosition = -1;
                        int visibleItemCount = layoutManager.getChildCount();
                        int totalItemCount = layoutManager.getItemCount();
    
                        if(layoutManager instanceof GridLayoutManager)
                        {
                            GridLayoutManager gridLayoutManager = (GridLayoutManager)layoutManager;
                            firstCompleteVisibleItemPosition = gridLayoutManager.findFirstCompletelyVisibleItemPosition();
                            lastCompleteVisibleItemPosition = gridLayoutManager.findLastCompletelyVisibleItemPosition();
                        }else if(layoutManager instanceof  LinearLayoutManager)
                        {
                            LinearLayoutManager linearLayoutManager = (LinearLayoutManager)layoutManager;
                            firstCompleteVisibleItemPosition = linearLayoutManager.findFirstCompletelyVisibleItemPosition();
                            lastCompleteVisibleItemPosition = linearLayoutManager.findLastCompletelyVisibleItemPosition();
                        }
    
                        String message = "";
    
                        // Means scroll at beginning ( top to bottom or left to right).
                        if(firstCompleteVisibleItemPosition == 0)
                        {
                            // dy < 0 means scroll to bottom, dx < 0 means scroll to right at beginning.
                            if(dy < 0 || dx < 0)
                            {
                                // Means scroll to bottom.
                                if(dy < 0)
                                {
                                    loadData(true);
                                }
    
                                // Means scroll to right.
                                if(dx < 0 )
                                {
                                    loadData(true);
                                }
                            }
                        }
                        // Means scroll at ending ( bottom to top or right to left )
                        else if(lastCompleteVisibleItemPosition == (totalItemCount - 1))
                        {
                            // dy > 0 means scroll to up, dx > 0 means scroll to left at ending.
                            if(dy > 0 || dx > 0)
                            {
                                // Scroll to top
                                if(dy > 0)
                                {
                                    loadData(false);
                                }
    
                                // Scroll to left
                                if(dx > 0 )
                                {
                                    loadData(false);
                                }
                            }
                        }
    
                        if(message.length() > 0) {
                            Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                        }
                    }
                });
            }
    
            if(uiHandler == null)
            {
                uiHandler = new Handler()
                {
                    @Override
                    public void handleMessage(Message msg) {
                        // If the message want to refresh list view.
                        if(msg.what == MESSAGE_UPDATE_RECYCLER_VIEW)
                        {
                            // Refresh list view after add item data.
                            customRecyclerViewDataAdapter.notifyDataSetChanged();
                        }
    
                        Bundle bundle = msg.getData();
                        int newItemIndex = bundle.getInt(MESSAGE_KEY_NEW_ITEM_INDEX);
                        recyclerView.scrollToPosition(newItemIndex - 1);
    
                        // Stop showing the progress bar.
                        progressBar.setVisibility(View.GONE);
                    }
                };
            }
    
            if(itemList == null)
            {
                itemList = new ArrayList<CustomRecyclerViewItem>();
                for(int i=0;i<6;i++)
                {
                    CustomRecyclerViewItem item = new CustomRecyclerViewItem();
                    item.setText("Card " + (i + 1));
                    itemList.add(item);
                }
            }
    
            if(progressBar == null)
            {
                progressBar = (ProgressBar)findViewById(R.id.custom_refresh_recycler_view_progressbar);
            }
        }
    
    
        private void loadData(final boolean insertDataAtBeginning)
        {
    
            // Show progressbar first.
            progressBar.setVisibility(View.VISIBLE);
    
            Thread workerThread = new Thread()
            {
                @Override
                public void run() {
                    try {
    
                        Thread.sleep(3000);
    
                        int currItemListSize = itemList.size();
    
                        int newItemIndex = 0;
    
                        // Only add one RecyclerView item.
                        for (int i = currItemListSize; i < currItemListSize + 1; i++){
    
                            CustomRecyclerViewItem newViewItem = new CustomRecyclerViewItem();
                            newViewItem.setText("Card " + (i + 1));
    
                            if (insertDataAtBeginning) {
                                itemList.add(i - currItemListSize, newViewItem);
                                newItemIndex = 0;
                            }else
                            {
                                itemList.add(newViewItem);
                                newItemIndex = itemList.size() - 1;
                            }
    
                            Message message = new Message();
                            message.what = MESSAGE_UPDATE_RECYCLER_VIEW;
                            Bundle bundle = new Bundle();
                            bundle.putInt(MESSAGE_KEY_NEW_ITEM_INDEX, newItemIndex);
                            message.setData(bundle);
                            uiHandler.sendMessage(message);
                        }
                    }catch(InterruptedException ex)
                    {
                        Log.e(LOG_TAG, ex.getMessage(), ex);
                    }
                }
            };
    
            workerThread.start();
        }
    }

3. Main Activity Layout XML File.

  1. This file is saved in the app/res/layout folder.
  2. activity_custom_refresh_recycler_view.xml
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/custom_refresh_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"/>
    
        <ProgressBar
            android:id="@+id/custom_refresh_recycler_view_progressbar"
            style="@android:style/Widget.Holo.Light.ProgressBar.Large.Inverse"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:foregroundGravity="center_vertical"
            android:visibility="gone" />
    
    </LinearLayout>

4. RecyclerView Data Adapter Class.

  1. CustomRecyclerViewDataAdapter.java
    package com.dev2qa.example.view.recycler_view;
    
    import android.support.v7.widget.RecyclerView.Adapter;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    import com.dev2qa.example.R;
    
    import java.util.List;
    
    public class CustomRecyclerViewDataAdapter extends Adapter<CustomRecyclerViewHolder> {
    
        private List<CustomRecyclerViewItem> viewItemList;
    
        public CustomRecyclerViewDataAdapter(List<CustomRecyclerViewItem> viewItemList) {
            this.viewItemList = viewItemList;
        }
    
        @Override
        public CustomRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            // Get LayoutInflater object.
            LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
            // Inflate the RecyclerView item layout xml.
            View itemView = layoutInflater.inflate(R.layout.activity_custom_refresh_recycler_view_item, parent, false);
    
            // Create and return our customRecycler View Holder object.
            CustomRecyclerViewHolder ret = new CustomRecyclerViewHolder(itemView);
            return ret;
        }
    
        @Override
        public void onBindViewHolder(CustomRecyclerViewHolder holder, int position) {
            if(viewItemList!=null) {
                // Get car item dto in list.
                CustomRecyclerViewItem viewItem = viewItemList.get(position);
    
                if(viewItem != null) {
                    // Set car item title.
                    holder.getTextView().setText(viewItem.getText());;
                }
            }
        }
    
        @Override
        public int getItemCount() {
            int ret = 0;
            if(viewItemList!=null)
            {
                ret = viewItemList.size();
            }
            return ret;
        }
    }

5. RecyclerView Item Layout XML File.

  1. This XML file is saved in app / res / layout folder.
  2. activity_custom_refresh_recycler_view_item.xml
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.CardView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:cardCornerRadius="8dp"
        app:cardElevation="10dp">
    
        <TextView
            android:id="@+id/custom_refresh_recycler_view_text_view"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:gravity="center"
            android:textSize="20dp"/>
    
    </android.support.v7.widget.CardView>

6. RecyclerView View Holder Class.

  1. CustomRecyclerViewHolder.java
    package com.dev2qa.example.view.recycler_view;
    
    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    import android.widget.TextView;
    
    import com.dev2qa.example.R;
    
    public class CustomRecyclerViewHolder extends RecyclerView.ViewHolder {
    
        private TextView textView = null;
    
        public CustomRecyclerViewHolder(View itemView) {
            super(itemView);
    
            if(itemView != null)
            {
                textView = (TextView)itemView.findViewById(R.id.custom_refresh_recycler_view_text_view);
            }
        }
    
        public TextView getTextView() {
            return textView;
        }
    }

7. RecyclerView View Item DTO Java File.

  1. CustomRecyclerViewItem.java
    package com.dev2qa.example.view.recycler_view;
    
    public class CustomRecyclerViewItem {
    
        private String text;
    
        public String getText() {
            return text;
        }
    
        public void setText(String text) {
            this.text = text;
        }
    }

8. Android Manifest Xml File.

  1. This file is saved in the app/manifests folder.
  2. AndroidManifest.xml
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.dev2qa.example">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            
            <activity android:name=".view.recycler_view.CustomRecyclerViewScrollActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

2 thoughts on “Android Recyclerview Horizontal Scroll Example”

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.