How to implement endless list with RecyclerView?

前端 未结 30 2692
无人及你
无人及你 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:01

    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<YourDataClass> data) {
    
        for (int i = 0; i < data.size(); i++) {
            YourDataClass yourDataObject = data.get(i);
            mLineItemList.add(new LineItem(yourDataObject));
            notifyItemInserted(mLineItemList.size() - 1);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 03:04

    My answer is a modified version of Noor. I passed from a ListView where i had EndlessScrollListener (that you can find easily in many answers on SO) to a RecyclerView so i wanted a EndlessRecyclScrollListener to easily update my past listener.

    So here is the code, hope it helps:

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

    Although the accepted answer works perfectly, the solution below uses addOnScrollListener since setOnScrollListener is deprecated, and reduces number of variables, and if 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();
                }
            }
        }
    });
    
    0 讨论(0)
  • 2020-11-22 03:04

    There is an easy to use library for this named paginate . Supports both ListView and RecyclerView ( LinearLayout , GridLayout and StaggeredGridLayout).

    Here is the link to the project on Github

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

    I would try to extend used LayoutManager (e.g. LinearLayoutManager) and override scrollVerticallyBy() method. Firstly, I would call super first and then check returned integer value. If the value equals to 0 then a bottom or a top border is reached. Then I would use findLastVisibleItemPosition() method to find out which border is reached and load more data if needed. Just an idea.

    In addition, you can even return your value from that method allowing overscroll and showing "loading" indicator.

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

    OK, I did it by using the onBindViewHolder method of RecyclerView.Adapter.

    Adapter:

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

    Fragment (or Activity):

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