How to implement endless list with RecyclerView?

前端 未结 30 2694
无人及你
无人及你 2020-11-22 02:22

I would like to change ListView to RecyclerView. I want to use the onScroll of the OnScrollListener in RecyclerView to determine if a

相关标签:
30条回答
  • 2020-11-22 03:16

    Most answer are assuming the RecyclerView uses a LinearLayoutManager, or GridLayoutManager, or even StaggeredGridLayoutManager, or assuming that the scrolling is vertical or horyzontal, but no one has posted a completly generic answer.

    Using the ViewHolder's adapter is clearly not a good solution. An adapter might have more than 1 RecyclerView using it. It "adapts" their contents. It should be the RecyclerView (which is the one class which is responsible of what is currently displayed to the user, and not the adapter which is responsible only to provide content to the RecyclerView) which must notify your system that more items are needed (to load).

    Here is my solution, using nothing else than the abstracted classes of the RecyclerView (RecycerView.LayoutManager and 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 triggered 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.
        }
    }
    
    0 讨论(0)
  • 2020-11-22 03:17

    Although there are so many answers to the question, I would like to share our experience of creating the endless list view. We have recently implemented custom Carousel LayoutManager that can work in the cycle by scrolling the list infinitely as well as up to a certain point. Here is a detailed description on GitHub.

    I suggest you take a look at this article with short but valuable recommendations on creating custom LayoutManagers: http://cases.azoft.com/create-custom-layoutmanager-android/

    0 讨论(0)
  • 2020-11-22 03:17

    @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;
            }
          }
        }
      }
    
    0 讨论(0)
  • 2020-11-22 03:19

    This solution works perfectly for me.

    //Listener    
    
    public abstract class InfiniteScrollListener     extendsRecyclerView.OnScrollListener {
    
    public static String 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);
    
    0 讨论(0)
  • 2020-11-22 03:20

    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
    
                }
            }
        });
    
    0 讨论(0)
  • 2020-11-22 03:21

    Try below:

    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);
    
    }
    
    0 讨论(0)
提交回复
热议问题