Comment mettre en œuvre une liste sans fin avec RecyclerView?

Je voudrais changer ListView à RecyclerView . Je veux utiliser le onScroll de OnScrollListener dans RecyclerView pour déterminer si un utilisateur a défilé jusqu’à la fin de la liste.

Comment savoir si un utilisateur passe à la fin de la liste pour pouvoir récupérer de nouvelles données à partir d’un service REST?

    Merci à @Kushal et voici comment je l’ai implémenté

     private boolean loading = true; int pastVisiblesItems, visibleItemCount, totalItemCount; mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if(dy > 0) //check for scroll down { visibleItemCount = mLayoutManager.getChildCount(); totalItemCount = mLayoutManager.getItemCount(); pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition(); if (loading) { if ( (visibleItemCount + pastVisiblesItems) >= totalItemCount) { loading = false; Log.v("...", "Last Item Wow !"); //Do pagination.. ie fetch new data } } } } }); 

    N’oubliez pas d’append

     LinearLayoutManager mLayoutManager; mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); 

    Faites ces variables.

     private int previousTotal = 0; private boolean loading = true; private int visibleThreshold = 5; int firstVisibleItem, visibleItemCount, totalItemCount; 

    Définir sur défilement pour la vue recycleur.

     mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); visibleItemCount = mRecyclerView.getChildCount(); totalItemCount = mLayoutManager.getItemCount(); firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); if (loading) { if (totalItemCount > previousTotal) { loading = false; previousTotal = totalItemCount; } } if (!loading && (totalItemCount - visibleItemCount) < = (firstVisibleItem + visibleThreshold)) { // End has been reached Log.i("Yaeye!", "end called"); // Do something loading = true; } } }); 

    Remarque: Assurez-vous que vous utilisez LinearLayoutManager tant que gestionnaire de disposition pour RecyclerView .

     LinearLayoutManager mLayoutManager; mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); 

    et pour une grid

     GridLayoutManager mLayoutManager; mLayoutManager = new GridLayoutManager(getActivity(), spanCount); mRecyclerView.setLayoutManager(mLayoutManager); 

    Amusez-vous avec vos rouleaux sans fin !! ^. ^

    Mise à jour: mRecyclerView. setOnScrollListener () est obsolète, remplacez simplement par mRecyclerView.addOnScrollListener() et l'avertissement disparaîtra! Vous pouvez en savoir plus sur cette question SO .

    Comme Android supporte maintenant officiellement Kotlin, voici une mise à jour pour le même -

    Make OnScrollListener

     class OnScrollListener(val layoutManager: LinearLayoutManager, val adapter: RecyclerView.Adapter, val dataList: MutableList) : RecyclerView.OnScrollListener() { var previousTotal = 0 var loading = true val visibleThreshold = 10 var firstVisibleItem = 0 var visibleItemCount = 0 var totalItemCount = 0 override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) visibleItemCount = recyclerView.childCount totalItemCount = layoutManager.itemCount firstVisibleItem = layoutManager.findFirstVisibleItemPosition() if (loading) { if (totalItemCount > previousTotal) { loading = false previousTotal = totalItemCount } } if (!loading && (totalItemCount - visibleItemCount) < = (firstVisibleItem + visibleThreshold)) { val initialSize = dataList.size updateDataList(dataList) val updatedSize = dataList.size recyclerView.post { adapter.notifyItemRangeInserted(initialSize, updatedSize) } loading = true } } } 

    et l'append à votre RecyclerView comme ceci

     recyclerView.addOnScrollListener(OnScrollListener(layoutManager, adapter, dataList)) 

    Pour un exemple de code complet, n'hésitez pas à vous référer à ce repository Github .

    Pour ceux qui veulent seulement être avertis lorsque le dernier élément est totalement affiché, vous pouvez utiliser View.canScrollVertically() .

    Voici ma mise en œuvre:

     public abstract class OnVerticalScrollListener extends RecyclerView.OnScrollListener { @Override public final void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (!recyclerView.canScrollVertically(-1)) { onScrolledToTop(); } else if (!recyclerView.canScrollVertically(1)) { onScrolledToBottom(); } else if (dy < 0) { onScrolledUp(); } else if (dy > 0) { onScrolledDown(); } } public void onScrolledUp() {} public void onScrolledDown() {} public void onScrolledToTop() {} public void onScrolledToBottom() {} } 

    Remarque: Vous pouvez utiliser recyclerView.getLayoutManager().canScrollVertically() si vous souhaitez prendre en charge l’API <14.

    Voici une autre approche. Cela fonctionnera avec n’importe quel gestionnaire de mise en page.

    1. Rendre la classe abstraite abstraite
    2. Ensuite, créez une méthode abstraite dans la classe de l’adaptateur (par exemple, load ())
    3. Dans onBindViewHolder, vérifiez la position si elle est en dernier et appelez load ()
    4. Remplacez la fonction load () lors de la création de l’object adaptateur dans votre activité ou fragment.
    5. Dans la fonction de chargement surchargé, implémentez votre appel loadmore

    Pour une compréhension plus détaillée, j’ai écrit un article sur le blog et un exemple de projet: http://sab99r.com/blog/recyclerview-endless-load-more/

    MyAdapter.java

     public abstract class MyAdapter extends RecyclerView.Adapter{ @Override public void onBindViewHolder(ViewHolder holder, int position) { //check for last item if ((position >= getItemCount() - 1)) load(); } public abstract void load(); } 

    MyActivity.java

     public class MainActivity extends AppCompatActivity { List items; MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { ... adapter=new MyAdapter(items){ @Override public void load() { //implement your load more here Item lastItem=items.get(items.size()-1); loadMore(); } }; } } 

    Ma réponse est une version modifiée de Noor. Je suis passé d’une ListViewEndlessScrollListener (que vous pouvez trouver facilement dans de nombreuses réponses sur SO) à un RecyclerView donc je voulais un EndlessRecyclScrollListener pour facilement mettre à jour mon ancien écouteur.

    Alors voici le code, j’espère que ça aide:

     public abstract class EndlessScrollRecyclListener extends RecyclerView.OnScrollListener { // The total number of items in the dataset after the last load private int previousTotalItemCount = 0; private boolean loading = true; private int visibleThreshold = 5; int firstVisibleItem, visibleItemCount, totalItemCount; private int startingPageIndex = 0; private int currentPage = 0; @Override public void onScrolled(RecyclerView mRecyclerView, int dx, int dy) { super.onScrolled(mRecyclerView, dx, dy); LinearLayoutManager mLayoutManager = (LinearLayoutManager) mRecyclerView .getLayoutManager(); visibleItemCount = mRecyclerView.getChildCount(); totalItemCount = mLayoutManager.getItemCount(); firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); onScroll(firstVisibleItem, visibleItemCount, totalItemCount); } public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) { // If the total item count is zero and the previous isn't, assume the // list is invalidated and should be reset back to initial state if (totalItemCount < previousTotalItemCount) { this.currentPage = this.startingPageIndex; this.previousTotalItemCount = totalItemCount; if (totalItemCount == 0) { this.loading = true; } } // If it's still loading, we check to see if the dataset count has // changed, if so we conclude it has finished loading and update the current page // number and total item count. if (loading && (totalItemCount > previousTotalItemCount)) { loading = false; previousTotalItemCount = totalItemCount; currentPage++; } // If it isn't currently loading, we check to see if we have breached // the visibleThreshold and need to reload more data. // If we do need to reload some more data, we execute onLoadMore to fetch the data. if (!loading && (totalItemCount - visibleItemCount) < = (firstVisibleItem + visibleThreshold)) { onLoadMore(currentPage + 1, totalItemCount); loading = true; } } // Defines the process for actually loading more data based on page public abstract void onLoadMore(int page, int totalItemsCount); } 

    Pour moi, c’est très simple:

      private boolean mLoading = false; mList.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int totalItem = mLinearLayoutManager.getItemCount(); int lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition(); if (!mLoading && lastVisibleItem == totalItem - 1) { mLoading = true; // Scrolled to bottom. Do something here. mLoading = false; } } }); 

    Soyez prudent avec les travaux asynchrones: mLoading doit être modifié à la fin des travaux asynchrones. J’espère que ce sera utile!

    La plupart des réponses LinearLayoutManager RecyclerView utilise un LinearLayoutManager , ou GridLayoutManager , ou même StaggeredGridLayoutManager , ou en supposant que le défilement est vertical ou horyzontal, mais personne n’a posté une réponse complètement générique .

    L’utilisation de l’adaptateur ViewHolder n’est clairement pas une bonne solution. Un adaptateur peut avoir plus de 1 RecyclerView utilisant. Il “adapte” leur contenu. Ce doit être la vue du recycleur (qui est la seule classe qui est responsable de ce qui est actuellement affiché à l’utilisateur, et non l’adaptateur qui est uniquement responsable de fournir du contenu à RecyclerView ) qui doit informer votre système charger).

    Voici ma solution, n’utilisant rien d’autre que les classes abstraites de RecyclerView (RecycerView.LayoutManager et RecycerView.Adapter):

     /** * Listener to callback when the last item of the adpater is visible to the user. * It should then be the time to load more items. **/ public abstract class LastItemListener extends RecyclerView.OnScrollListener { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // init RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); RecyclerView.Adapter adapter = recyclerView.getAdapter(); if (layoutManager.getChildCount() > 0) { // Calculations.. int indexOfLastItemViewVisible = layoutManager.getChildCount() -1; View lastItemViewVisible = layoutManager.getChildAt(indexOfLastItemViewVisible); int adapterPosition = layoutManager.getPosition(lastItemViewVisible); boolean isLastItemVisible = (adapterPosition == adapter.getItemCount() -1); // check if (isLastItemVisible) onLastItemVisible(); // callback } } /** * Here you should load more items because user is seeing the last item of the list. * Advice: you should add a bollean value to the class * so that the method {@link #onLastItemVisible()} will be sortingggered only once * and not every time the user touch the screen ;) **/ public abstract void onLastItemVisible(); } // --- Exemple of use --- myRecyclerView.setOnScrollListener(new LastItemListener() { public void onLastItemVisible() { // start to load more items here. } } 

    Bien que la réponse acceptée fonctionne parfaitement, la solution ci-dessous utilise addOnScrollListener, car setOnScrollListener est obsolète et réduit le nombre de variables et les conditions.

     final LinearLayoutManager layoutManager = new LinearLayoutManager(context); feedsRecyclerView.setLayoutManager(layoutManager); feedsRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (dy > 0) { if ((layoutManager.getChildCount() + layoutManager.findFirstVisibleItemPosition()) >= layoutManager.getItemCount()) { Log.d("TAG", "End of list"); //loadMore(); } } } }); 

    Bien qu’il y ait tant de réponses à la question, j’aimerais partager notre expérience de la création de la vue de liste sans fin. Nous avons récemment implémenté Carousel LayoutManager personnalisé qui peut fonctionner dans le cycle en faisant défiler la liste à l’infini et jusqu’à un certain point. Voici une description détaillée sur GitHub .

    Je vous suggère de jeter un oeil à cet article avec des recommandations courtes mais précieuses sur la création de LayoutManagers personnalisés: http://cases.azoft.com/create-custom-layoutmanager-android/

    Mon moyen de détecter un événement de chargement n’est pas de détecter le défilement, mais d’écouter si la dernière vue a été jointe. Si la dernière vue était jointe, je la considère comme un timing pour charger plus de contenu.

     class MyListener implements RecyclerView.OnChildAttachStateChangeListener { RecyclerView mRecyclerView; MyListener(RecyclerView view) { mRecyclerView = view; } @Override public void onChildViewAttachedToWindow(View view) { RecyclerView.Adapter adapter = mRecyclerView.getAdapter(); RecyclerView.LayoutManager mgr = mRecyclerView.getLayoutManager(); int adapterPosition = mgr.getPosition(view); if (adapterPosition == adapter.getItemCount() - 1) { // last view was attached loadMoreContent(); } @Override public void onChildViewDetachedFromWindow(View view) {} } 

    OK, je l’ai fait en utilisant la méthode onBindViewHolder de RecyclerView.Adapter.

    Adaptateur:

     public interface OnViewHolderListener { void onRequestedLastItem(); } @Override public void onBindViewHolder(ViewHolder holder, int position) { ... if (position == getItemCount() - 1) onViewHolderListener.onRequestedLastItem(); } 

    Fragment (ou activité) :

     @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { contentView = inflater.inflate(R.layout.comments_list, container, false); recyclerView = (RecyclerView) mContentView.findViewById(R.id.my_recycler_view); adapter = new Adapter(); recyclerView.setAdapter(adapter); ... adapter.setOnViewHolderListener(new Adapter.OnViewHolderListener() { @Override public void onRequestedLastItem() { //TODO fetch new data from webservice } }); return contentView; } 

    J’essaierais d’étendre la LayoutManager (par exemple LinearLayoutManager ) et de remplacer la méthode scrollVerticallyBy() . Tout d’abord, j’appellerais super premier et ensuite vérifier la valeur entière retournée. Si la valeur est égale à 0 une bordure inférieure ou supérieure est atteinte. Ensuite, j’utiliserais la méthode findLastVisibleItemPosition() pour trouver la bordure atteinte et charger plus de données si nécessaire. Juste une idée.

    De plus, vous pouvez même renvoyer votre valeur à partir de cette méthode, ce qui permet de faire défiler les données et d’afficher un indicateur de «chargement».

    J’ai réalisé une implémentation de type défilement infini en utilisant cette logique dans la méthode onBindViewHolder de ma classe RecyclerView.Adapter .

      if (position == mItems.size() - 1 && mCurrentPage < = mTotalPageCount) { if (mCurrentPage == mTotalPageCount) { mLoadImagesListener.noMorePages(); } else { int newPage = mCurrentPage + 1; mLoadImagesListener.loadPage(newPage); } } 

    Avec ce code lorsque RecyclerView arrive au dernier élément, il incrémente la page en cours et les rappels sur une interface chargée de charger plus de données à partir de l'API et d'append les nouveaux résultats à l'adaptateur.

    Je peux poster un exemple plus complet si ce n'est pas clair?

    Pour les personnes qui utilisent StaggeredGridLayoutManager, voici mon implémentation, cela fonctionne pour moi.

      private class ScrollListener extends RecyclerView.OnScrollListener { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { firstVivisibleItems = mLayoutManager.findFirstVisibleItemPositions(firstVivisibleItems); if(!recyclerView.canScrollVertically(1) && firstVivisibleItems[0]!=0) { loadMoreImages(); } } private boolean loadMoreImages(){ Log.d("myTag", "LAST-------HERE------"); return true; } } 

    Il y a une bibliothèque facile à utiliser pour cette pagination nommée. Prend en charge à la fois ListView et RecyclerView (LinearLayout, GridLayout et StaggeredGridLayout).

    Voici le lien vers le projet sur Github

    Avec la puissance des fonctions d’extension de Kotlin, le code peut paraître beaucoup plus élégant. Mettez ceci partout où vous voulez (je l’ai dans un fichier ExtensionFunctions.kt):

     /** * WARNING: This assumes the layout manager is a LinearLayoutManager */ fun RecyclerView.addOnScrolledToEnd(onScrolledToEnd: () -> Unit){ this.addOnScrollListener(object: RecyclerView.OnScrollListener(){ private val VISIBLE_THRESHOLD = 5 private var loading = true private var previousTotal = 0 override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { with(layoutManager as LinearLayoutManager){ val visibleItemCount = childCount val totalItemCount = itemCount val firstVisibleItem = findFirstVisibleItemPosition() if (loading && totalItemCount > previousTotal){ loading = false previousTotal = totalItemCount } if(!loading && (totalItemCount - visibleItemCount) < = (firstVisibleItem + visibleThreshold)){ onScrolledToEnd() loading = true } } } }) } 

    Et puis utilisez-le comme ceci:

     youRecyclerView.addOnScrolledToEnd { //What you want to do once the end is reached } 

    Cette solution est basée sur la réponse de Kushal Sharma. Cependant, c'est un peu mieux parce que:

    1. Il utilise onScrollStateChanged au lieu de onScroll . C'est mieux parce que onScroll est appelé chaque fois qu'il y a un mouvement quelconque dans RecyclerView, alors que onScrollStateChanged est uniquement appelé lorsque l'état de RecyclerView est modifié. L'utilisation de onScrollStateChanged permettra d'économiser du temps CPU et, par conséquent, de la batterie.
    2. Puisque cela utilise des fonctions d'extension, cela peut être utilisé dans n'importe quelle RecyclerView que vous avez. Le code client est juste une ligne.

    J’ai un exemple assez détaillé de la façon de paginer avec un RecyclerView. A un niveau élevé, j’ai un ensemble PAGE_SIZE, disons 30. Je demande donc 30 éléments et si je récupère 30, je demande la page suivante. Si je reçois moins de 30 éléments, je marque une variable pour indiquer que la dernière page a été atteinte, puis je cesse de demander plus de pages. Vérifiez-le et dites-moi ce que vous en pensez.

    https://medium.com/@etiennelawlor/pagination-with-recyclerview-1cb7e66a502b

    Ici, ma solution utilisant AsyncListUtil , sur le Web, dit: Notez que cette classe utilise un seul thread pour charger les données, de sorte qu’il convient de charger des données à partir d’un stockage secondaire tel qu’un disque, mais pas à partir du réseau. mais j’utilise odata pour lire les données et travailler correctement. Je manque dans mes exemples d’entités de données et de méthodes de réseau. J’inclus uniquement l’adaptateur d’exemple.

     public class AsyncPlatoAdapter extends RecyclerView.Adapter { private final AsyncPlatoListUtil mAsyncListUtil; private final MainActivity mActivity; private final RecyclerView mRecyclerView; private final Ssortingng mFilter; private final Ssortingng mOrderby; private final Ssortingng mExpand; public AsyncPlatoAdapter(Ssortingng filter, Ssortingng orderby, Ssortingng expand, RecyclerView recyclerView, MainActivity activity) { mFilter = filter; mOrderby = orderby; mExpand = expand; mRecyclerView = recyclerView; mActivity = activity; mAsyncListUtil = new AsyncPlatoListUtil(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()). inflate(R.layout.plato_cardview, parent, false); // Create a ViewHolder to find and hold these view references, and // register OnClick with the view holder: return new PlatoViewHolderAsync(itemView, this); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final Plato item = mAsyncListUtil.getItem(position); PlatoViewHolderAsync vh = (PlatoViewHolderAsync) holder; if (item != null) { Integer imagen_id = item.Imagen_Id.get(); vh.getBinding().setVariable(BR.plato, item); vh.getBinding().executePendingBindings(); vh.getImage().setVisibility(View.VISIBLE); vh.getProgress().setVisibility(View.GONE); Ssortingng cacheName = null; Ssortingng urlSsortingng = null; if (imagen_id != null) { cacheName = Ssortingng.format("imagenes/imagen/%d", imagen_id); urlSsortingng = Ssortingng.format("%s/menusapi/%s", MainActivity.ROOTPATH, cacheName); } ImageHelper.downloadBitmap(mActivity, vh.getImage(), vh.getProgress(), urlSsortingng, cacheName, position); } else { vh.getBinding().setVariable(BR.plato, item); vh.getBinding().executePendingBindings(); //show progress while loading. vh.getImage().setVisibility(View.GONE); vh.getProgress().setVisibility(View.VISIBLE); } } @Override public int getItemCount() { return mAsyncListUtil.getItemCount(); } public class AsyncPlatoListUtil extends AsyncListUtil { /** * Creates an AsyncListUtil. */ public AsyncPlatoListUtil() { super(Plato.class, //my data class 10, //page size new DataCallback() { @Override public int refreshData() { //get count calling ../$count ... odata endpoint return countPlatos(mFilter, mOrderby, mExpand, mActivity); } @Override public void fillData(Plato[] data, int startPosition, int itemCount) { //get items from odata endpoint using $skip and $top Platos p = loadPlatos(mFilter, mOrderby, mExpand, startPosition, itemCount, mActivity); for (int i = 0; i < Math.min(itemCount, p.value.size()); i++) { data[i] = p.value.get(i); } } }, new ViewCallback() { @Override public void getItemRangeInto(int[] outRange) { //i use LinearLayoutManager in the RecyclerView LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); outRange[0] = layoutManager.findFirstVisibleItemPosition(); outRange[1] = layoutManager.findLastVisibleItemPosition(); } @Override public void onDataRefresh() { mRecyclerView.getAdapter().notifyDataSetChanged(); } @Override public void onItemLoaded(int position) { mRecyclerView.getAdapter().notifyItemChanged(position); } }); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { onRangeChanged(); } }); } } } 

    @kushal @abdulaziz

    Why not use this logic instead?

     public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int totalItemCount, lastVisibleItemPosition; if (dy > 0) { totalItemCount = _layoutManager.getItemCount(); lastVisibleItemPosition = _layoutManager.findLastVisibleItemPosition(); if (!_isLastItem) { if ((totalItemCount - 1) == lastVisibleItemPosition) { LogUtil.e("end_of_list"); _isLastItem = true; } } } } 

    Essayez ci-dessous:

     import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.LayoutManager; /** * Abstract Endless ScrollListener * */ public abstract class EndlessScrollListener extends RecyclerView.OnScrollListener { // The minimum amount of items to have below your current scroll position // before loading more. private int visibleThreshold = 10; // The current offset index of data you have loaded private int currentPage = 1; // True if we are still waiting for the last set of data to load. private boolean loading = true; // The total number of items in the data set after the last load private int previousTotal = 0; private int firstVisibleItem; private int visibleItemCount; private int totalItemCount; private LayoutManager layoutManager; public EndlessScrollListener(LayoutManager layoutManager) { validateLayoutManager(layoutManager); this.layoutManager = layoutManager; } public EndlessScrollListener(int visibleThreshold, LayoutManager layoutManager, int startPage) { validateLayoutManager(layoutManager); this.visibleThreshold = visibleThreshold; this.layoutManager = layoutManager; this.currentPage = startPage; } private void validateLayoutManager(LayoutManager layoutManager) throws IllegalArgumentException { if (null == layoutManager || !(layoutManager instanceof GridLayoutManager) || !(layoutManager instanceof LinearLayoutManager)) { throw new IllegalArgumentException( "LayoutManager must be of type GridLayoutManager or LinearLayoutManager."); } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); visibleItemCount = recyclerView.getChildCount(); totalItemCount = layoutManager.getItemCount(); if (layoutManager instanceof GridLayoutManager) { firstVisibleItem = ((GridLayoutManager) layoutManager) .findFirstVisibleItemPosition(); } else if (layoutManager instanceof LinearLayoutManager) { firstVisibleItem = ((LinearLayoutManager) layoutManager) .findFirstVisibleItemPosition(); } if (loading) { if (totalItemCount > previousTotal) { loading = false; previousTotal = totalItemCount; } } if (!loading && (totalItemCount - visibleItemCount) < = (firstVisibleItem + visibleThreshold)) { // End has been reached do something currentPage++; onLoadMore(currentPage); loading = true; } } // Defines the process for actually loading more data based on page public abstract void onLoadMore(int page); } 

    I have created LoadMoreRecyclerView using Abdulaziz Noor Answer

    LoadMoreRecyclerView

     public class LoadMoreRecyclerView extends RecyclerView { private boolean loading = true; int pastVisiblesItems, visibleItemCount, totalItemCount; //WrapperLinearLayout is for handling crash in RecyclerView private WrapperLinearLayout mLayoutManager; private Context mContext; private OnLoadMoreListener onLoadMoreListener; public LoadMoreRecyclerView(Context context) { super(context); mContext = context; init(); } public LoadMoreRecyclerView(Context context, @Nullable AtsortingbuteSet attrs) { super(context, attrs); mContext = context; init(); } public LoadMoreRecyclerView(Context context, @Nullable AtsortingbuteSet attrs, int defStyle) { super(context, attrs, defStyle); mContext = context; init(); } private void init(){ mLayoutManager = new WrapperLinearLayout(mContext,LinearLayoutManager.VERTICAL,false); this.setLayoutManager(mLayoutManager); this.setItemAnimator(new DefaultItemAnimator()); this.setHasFixedSize(true); } @Override public void onScrolled(int dx, int dy) { super.onScrolled(dx, dy); if(dy > 0) //check for scroll down { visibleItemCount = mLayoutManager.getChildCount(); totalItemCount = mLayoutManager.getItemCount(); pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition(); if (loading) { if ( (visibleItemCount + pastVisiblesItems) >= totalItemCount) { loading = false; Log.v("...", "Call Load More !"); if(onLoadMoreListener != null){ onLoadMoreListener.onLoadMore(); } //Do pagination.. ie fetch new data } } } } @Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); } public void onLoadMoreCompleted(){ loading = true; } public void setMoreLoading(boolean moreLoading){ loading = moreLoading; } public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) { this.onLoadMoreListener = onLoadMoreListener; } } 

    WrapperLinearLayout

     public class WrapperLinearLayout extends LinearLayoutManager { public WrapperLinearLayout(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { super.onLayoutChildren(recycler, state); } catch (IndexOutOfBoundsException e) { Log.e("probe", "meet a IOOBE in RecyclerView"); } } } 

    //Add it in xml like

       

    OnCreate or onViewCreated

     mLoadMoreRecyclerView = (LoadMoreRecyclerView) view.findViewById(R.id.recycler_view); mLoadMoreRecyclerView.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { callYourService(StartIndex); } }); 

    callYourService

     private void callYourService(){ //callyour Service and get response in any List List newDataFromServer = getDataFromServerService(); //Enable Load More mLoadMoreRecyclerView.onLoadMoreCompleted(); if(newDataFromServer != null && newDataFromServer.size() > 0){ StartIndex += newDataFromServer.size(); if (newDataFromServer.size() < Integer.valueOf(MAX_ROWS)) { //StopLoading.. mLoadMoreRecyclerView.setMoreLoading(false); } } else{ mLoadMoreRecyclerView.setMoreLoading(false); mAdapter.notifyDataSetChanged(); } } 

    This is how I do it, simple and short:

      recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if(!recyclerView.canScrollVertically(1) && dy != 0) { // Load more results here } } }); 
      recyclerList.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx,int dy) { super.onScrolled(recyclerView, dx, dy); } @Override public void onScrollStateChanged(RecyclerView recyclerView,int newState) { int totalItemCount = layoutManager.getItemCount(); int lastVisibleItem = layoutManager.findLastVisibleItemPosition(); if (totalItemCount> 1) { if (lastVisibleItem >= totalItemCount - 1) { // End has been reached // do something } } } }); 

    Check this every thing is explained in detail: Pagination using RecyclerView From A to Z

      mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int visibleItemCount = mLayoutManager.getChildCount(); int totalItemCount = mLayoutManager.getItemCount(); int firstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition(); if (!mIsLoading && !mIsLastPage) { if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0) { loadMoreItems(); } } } }) 

    loadMoreItems():

     private void loadMoreItems() { mAdapter.removeLoading(); //load data here from the server // in case of success mAdapter.addData(data); // if there might be more data mAdapter.addLoading(); } 

    in MyAdapter :

     private boolean mIsLoadingFooterAdded = false; public void addLoading() { if (!mIsLoadingFooterAdded) { mIsLoadingFooterAdded = true; mLineItemList.add(new LineItem()); notifyItemInserted(mLineItemList.size() - 1); } } public void removeLoading() { if (mIsLoadingFooterAdded) { mIsLoadingFooterAdded = false; int position = mLineItemList.size() - 1; LineItem item = mLineItemList.get(position); if (item != null) { mLineItemList.remove(position); notifyItemRemoved(position); } } } public void addData(List data) { for (int i = 0; i < data.size(); i++) { YourDataClass yourDataObject = data.get(i); mLineItemList.add(new LineItem(yourDataObject)); notifyItemInserted(mLineItemList.size() - 1); } } 

    None of these answers take into account if the list is too small or not.

    Here’s a piece of code I’ve been using that works on RecycleViews in both directions.

     @Override public boolean onTouchEvent(MotionEvent motionEvent) { if (recyclerViewListener == null) { return super.onTouchEvent(motionEvent); } /** * If the list is too small to scroll. */ if (motionEvent.getAction() == MotionEvent.ACTION_UP) { if (!canScrollVertically(1)) { recyclerViewListener.reachedBottom(); } else if (!canScrollVertically(-1)) { recyclerViewListener.reachedTop(); } } return super.onTouchEvent(motionEvent); } public void setListener(RecyclerViewListener recycleViewListener) { this.recyclerViewListener = recycleViewListener; addOnScrollListener(new OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (recyclerViewListener == null) { return; } recyclerViewListener.scrolling(dy); if (!canScrollVertically(1)) { recyclerViewListener.reachedBottom(); } else if (!canScrollVertically(-1)) { recyclerViewListener.reachedTop(); } } }); } 

    I let you my aproximation. Fonctionne bien pour moi.

    J’espère que ça t’aide.

     /** * Created by Daniel Pardo Ligorred on 03/03/2016. */ public abstract class BaseScrollListener extends RecyclerView.OnScrollListener { protected RecyclerView.LayoutManager layoutManager; public BaseScrollListener(RecyclerView.LayoutManager layoutManager) { this.layoutManager = layoutManager; this.init(); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); this.onScroll(recyclerView, this.getFirstVisibleItem(), this.layoutManager.getChildCount(), this.layoutManager.getItemCount(), dx, dy); } private int getFirstVisibleItem(){ if(this.layoutManager instanceof LinearLayoutManager){ return ((LinearLayoutManager) this.layoutManager).findFirstVisibleItemPosition(); } else if (this.layoutManager instanceof StaggeredGridLayoutManager){ int[] spanPositions = null; //Should be null -> StaggeredGridLayoutManager.findFirstVisibleItemPositions makes the work. try{ return ((StaggeredGridLayoutManager) this.layoutManager).findFirstVisibleItemPositions(spanPositions)[0]; }catch (Exception ex){ // Do stuff... } } return 0; } public abstract void init(); protected abstract void onScroll(RecyclerView recyclerView, int firstVisibleItem, int visibleItemCount, int totalItemCount, int dx, int dy); } 

    It is also possible to implement without the scroll listener, using the pure logic of the data model alone. The scroll view requires to get items by position as well as the maximal item count. The model can have the background logic to fetch the needed items in chunks, rather than one by one, and do this in the background thread, notifying the view when the data are ready.

    This approach allows to have the fetching queue which prefers most recently requested (so currently visible) items over older (most likely already scrolled away) submissions, control the number of parallel threads to use and things the like. The complete source code for this approach (demo app and reusable library) are available here .

    This solution works perfectly for me.

     //Listener public abstract class InfiniteScrollListener extendsRecyclerView.OnScrollListener { public static Ssortingng TAG = InfiniteScrollListener.class.getSimpleName(); int firstVisibleItem, visibleItemCount, totalItemCount; private int previousTotal = 0; private boolean loading = true; private int visibleThreshold = 1; private int current_page = 1; private LinearLayoutManager mLinearLayoutManager; public InfiniteScrollListener(LinearLayoutManager linearLayoutManager) { this.mLinearLayoutManager = linearLayoutManager; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); visibleItemCount = recyclerView.getChildCount(); totalItemCount = mLinearLayoutManager.getItemCount(); firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition(); if (loading) { if (totalItemCount > previousTotal) { loading = false; previousTotal = totalItemCount; } } if (!loading && (totalItemCount - visibleItemCount - firstVisibleItem < = visibleThreshold)) { current_page++; onLoadMore(current_page); loading = true; } } public void resetState() { loading = true; previousTotal = 0; current_page = 1; } public abstract void onLoadMore(int current_page); } //Implementation into fragment private InfiniteScrollListener scrollListener; scrollListener = new InfiniteScrollListener(manager) { @Override public void onLoadMore(int current_page) { //Load data } }; rv.setLayoutManager(manager); rv.addOnScrollListener(scrollListener); 

    @erdna Please refer my below code.May be it will become helpful to you.

      int firstVisibleItem, visibleItemCount, totalItemCount; recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); visibleItemCount = layoutManager.getChildCount(); totalItemCount = layoutManager.getItemCount(); firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); Log.e("firstVisibleItem", firstVisibleItem + ""); Log.e("visibleItemCount", visibleItemCount + ""); Log.e("totalItemCount", totalItemCount + ""); if (page != total_page_index) { if (loading) { if ((visibleItemCount + firstVisibleItem) >= totalItemCount) { Log.e("page", Ssortingng.valueOf(page)); page=page+1; new GetSummary().execute(Ssortingng.valueOf(page), ""); loading = false; } } } } }); 
     if (layoutManager.findLastCompletelyVisibleItemPosition() == recyclerAdapter.getItemCount() - 1) { //load more items. } 

    Fair and simple. Cela fonctionnera.