In this article, we are going to see how to build an endless RecyclerView in Android Studio. It is mostly used to design the user interface with great control over the lists and grids of android applications. We can implement both horizontal and vertical layouts using RecyclerView. Here, we will be creating a RecyclerView with a load more option. A sample video is shown below to get an idea about what we are going to do in this article. Note that we will be using Java as the programming language.
Step by Step Implementation
Step 1: Create a New Project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Java as the programming language.
Step 2: Working with the activity_main.xml file
Navigate to the app > res > layout > activity_main.xml and add the below code to that file. Below is the code for the activity_main.xml file.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" tools:context = ".MainActivity" > <!--RecyclerView is Added. The attribute app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" is used for Linear Layout Manager--> < androidx.recyclerview.widget.RecyclerView android:id = "@+id/recyclerView" android:layout_width = "match_parent" android:layout_height = "match_parent" app:layoutManager = "androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintBottom_toBottomOf = "parent" app:layout_constraintLeft_toLeftOf = "parent" app:layout_constraintRight_toRightOf = "parent" app:layout_constraintTop_toTopOf = "parent" /> </ androidx.constraintlayout.widget.ConstraintLayout > |
Step 3: Create a New layout Resource File
Create a new Layout Resource File with name item_row.xml. To create a new Layout Resource File, Navigate to res > layout. Right-click on the layout folder then click on New and then click on Layout Resource File, a dialogue box is opened, add a name to your Layout Resource File and then click on the OK button. Your new Layout Resource File is created. Follow the images given below:
Step 4: Working with the item_row.xml file
Go to layout > item_row.xml file and add the below code to that file. Here the layout for the rows of RecyclerView is defined.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < androidx.cardview.widget.CardView android:layout_width = "match_parent" android:layout_height = "match_parent" app:cardElevation = "8dp" app:cardUseCompatPadding = "true" > <!--TextView Added for the layout of rows of the recyclerview--> < TextView android:id = "@+id/tvItem" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:padding = "16dp" android:text = "Item X" /> </ androidx.cardview.widget.CardView > |
Step 5: Again Create a New layout Resource File
Create a new Layout Resource File with name item_loading.xml. To create a new Layout Resource File, Navigate to res > layout. Right-click on the layout folder then click on New and then click on Layout Resource File, a dialogue box is opened, add a name to your Layout Resource File and then click on the OK button. Your new Layout Resource File is created. Follow the images given below:
Step 6: Working with the item_loading.xml file
Go to layout > item_loading.xml file and add the below code to that file. Here the layout for the loading view is defined.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:orientation = "vertical" > <!--ProgressBar is added to show the progress of the content--> < ProgressBar android:id = "@+id/progressbar" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_gravity = "center_horizontal" android:indeterminate = "true" android:paddingLeft = "8dp" android:paddingRight = "8dp" tools:ignore = "MissingConstraints" /> </ androidx.constraintlayout.widget.ConstraintLayout > |
Step 7: Create an Adapter class for RecyclerView
Create an adapter class for RecyclerView with the name RecyclerViewAdapter. To create the adapter class, you have to follow the images given below:
After adding a name to the adapter class press enter. Your RecycleviewAdapter.java file has been created.
Step 8: Working With the RecyclerViewAdapter.java file
Go to the RecyclerViewAdapter.java file and add the code given below to that file. Comments are added inside the code to understand the code in more detail.
Java
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.util.List; public class RecylerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private final int VIEW_TYPE_ITEM = 0 ; private final int VIEW_TYPE_LOADING = 1 ; private List<String> mItemList; public RecylerViewAdapter(List<String> itemList) { mItemList = itemList; } // Based on the View type we are instantiating the // ViewHolder in the onCreateViewHolder() method @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder( @NonNull ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false ); return new ItemViewHolder(view); } else { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false ); return new LoadingviewHolder(view); } } // Inside the onBindViewHolder() method we // are checking the type of ViewHolder // instance and populating the row accordingly @Override public void onBindViewHolder( @NonNull RecyclerView.ViewHolder holder, int position) { if (holder instanceof ItemViewHolder) { populateItemRows((ItemViewHolder) holder, position); } else if (holder instanceof LoadingviewHolder) { showLoadingView((LoadingviewHolder) holder, position); } } // getItemCount() method returns the size of the list @Override public int getItemCount() { return mItemList == null ? 0 : mItemList.size(); } // getItemViewType() method is the method where we check each element // of the list. If the element is NULL we set the view type as 1 else 0 public int getItemViewType( int position) { return mItemList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM; } public class ItemViewHolder extends RecyclerView.ViewHolder { TextView tvItem; public ItemViewHolder( @NonNull View itemView) { super (itemView); tvItem = itemView.findViewById(R.id.tvItem); } } private class LoadingviewHolder extends RecyclerView.ViewHolder { ProgressBar progressBar; public LoadingviewHolder( @NonNull View itemView) { super (itemView); progressBar = itemView.findViewById(R.id.progressbar); } } private void showLoadingView(LoadingviewHolder viewHolder, int position) { // Progressbar would be displayed } private void populateItemRows(ItemViewHolder viewHolder, int position) { String item = mItemList.get(position); viewHolder.tvItem.setText(item); } } |
Step 9: Working with the MainActivity.java file
Go to the MainActivity.java file and the code given below to that file. In MainActivity.java class we will be instantiating the above Adapter. Comments are added inside the code to understand the code in more detail.
Java
import android.os.Bundle; import android.os.Handler; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { RecyclerView recyclerView; RecylerViewAdapter recylerViewAdapter; ArrayList<String> rowsArrayList = new ArrayList<>(); boolean isLoading = false ; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recyclerView); // Following three methods have // been implemented in this class. populateData(); initAdapter(); initScrollListener(); } // PopulateData() method shows after how many items load more option // should be made available. In our case, i have taken 20 items private void populateData() { int i = 0 ; while (i < 20 ) { rowsArrayList.add( "ITEM " + i); i++; } } // initAdapter() method initiates the RecyclerViewAdapter private void initAdapter() { recylerViewAdapter = new RecylerViewAdapter(rowsArrayList); recyclerView.setAdapter(recylerViewAdapter); } // initScrollListener() method is the method where we are checking // the scrolled state of the RecyclerView and if bottom-most is visible // we are showing the loading view and populating the next list private void initScrollListener() { recyclerView.addOnScrollListener( new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged( @NonNull RecyclerView recyclerView, int newState) { super .onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled( @NonNull RecyclerView recyclerView, int dx, int dy) { super .onScrolled(recyclerView, dx, dy); LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (!isLoading) { if (linearLayoutManager != null && linearLayoutManager.findLastCompletelyVisibleItemPosition() == rowsArrayList.size() - 1 ) { // bottom of list! loadMore(); isLoading = true ; } } } } ); } // LoadMore() method is used to implement // the functionality of load more private void loadMore() { rowsArrayList.add( null ); recylerViewAdapter.notifyItemInserted(rowsArrayList.size() - 1 ); Handler handler = new Handler(); handler.postDelayed( new Runnable() { @Override public void run() { rowsArrayList.remove(rowsArrayList.size() - 1 ); int scrollPosition = rowsArrayList.size(); recylerViewAdapter.notifyItemRemoved(scrollPosition); int currentSize = scrollPosition; // Next load more option is to be shown after every 10 items. int nextLimit = currentSize + 10 ; while (currentSize - 1 < nextLimit) { rowsArrayList.add( "Item " + currentSize); currentSize++; } recylerViewAdapter.notifyDataSetChanged(); isLoading = false ; } }, 2000 ); } } |
Output: