Search code examples
androidandroid-recyclerviewonscrolllistener

Adding items to Endless Scroll RecyclerView with a ReverseLayout recyclerview


In a normal recyclerview, the newest items are all at the top and if you add an item into the recyclerview, it pushes the existing items down and the new item takes the top position.

In a reverseLayout recyclerview, the newest items are all at the bottom and if you add an item into the recyclerview, it is added right at the bottom. This kind of layout is quite useful for things like comment feeds where you expect the latest comments to be at the bottom.

A good example of this is the Facebook comment feed when you comment on a friend's status for example. You can see that the comments all have the time that they were posted at the bottom and the times are decreasing from 12 hours to 10 hours from top to bottom:

facebook comment feed

The reverseLayout is quite easy to set and I have done it using this code:

mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);

I'm however struggling to attach a reverse endless scroll listener. I'm using the following Vilen's code from my question a while back (Adding items to Endless Scroll RecyclerView with ProgressBar at bottom) and modifying it so that it the onLoadMoreListener will only activate itself when it is scrolling up instead of down. You want to scroll up to older comments:

    if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
        final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        //if you add on addOnScrollListener, it will cause the scroll listener to be called twice each time you reset your adapter
        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            int firstVisibleItem;
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                final int currentFirstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();

                if(lastVisibleItem > firstVisibleItem)
                {
                    Log.i("SCROLLING UP","TRUE");
                    if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                        current_page++;
                        if (onLoadMoreListener != null) {
                            onLoadMoreListener.onLoadMore(current_page);
                        }
                        loading = true;
                    }
                }
                lastVisibleItem=firstVisibleItem;
            }
        });
    }

When the onLoadMoreListener is called, the following code is called in my activity class:

    CommentsAdapter.OnLoadMoreListener onLoadMoreListener = new CommentsAdapter.OnLoadMoreListener() {
    @Override
    public void onLoadMore(int current_page) {
        //get the firstCommentId on the list of comments so that we can send it to the server to fetch comments less than that comment id to display in our recyclerview
        firstCommentId = comments.get(0).getId();
        //add empty item for progress bar / wheel and display the progress bar / wheel
        Comment comment = new Comment();
        comment.setViewType(Constants.COMMENT_PROGRESS_BAR);
        comments.add(0, comment);
        mCommentAdapter.notifyItemInserted(0);
        mCommentAdapter.notifyItemRangeChanged(1, comments.size());

        //CODE FOR NETWORK OPERATIONS GOES HERE TO FETCH THE NEXT FEW COMMENTS WHEN SCROLLING UP//
    }
};

However, the onLoadMoreListener doesn't seem to be called at all when I scroll up.

I also made sure I had at least 10 comments in my feed and 5 was loaded before and 5 more should be loaded when I scroll up.

Does anything know what I'm doing wrong with this reverse OnLoadMoreListener?

EDIT:

The reverseLayout recyclerview actually does work with the original code from Vilen, I have uploaded a github repo to show this:

https://github.com/Winghin2517/ReverseLayoutRecyclerview

There is still an issue with when the onLoadMoreListener is activated though - If the comment list only comprises of 3 comments and there is no more comments to add on, I don't want the onLoadMoreListener to activate at all when I initially view my comments - when I first click on my app to see the comments. Right now, when I click to view my comments, even though there are 3 comments in the Dataset, the progressBar is still displayed and the disappears after a 2 seconds which I think is not necessary (see github repo where I demonstrate this).

Disabling it when there is only 3 comments is also not a good idea as the onLoadMoreListener acts as like a swipeToRefresh object. If there are more comments from the user subsequent to when he views the comment feed, he can swipe down and the onLoadMoreListener will display those comments.

Is there a way to just disable it when the feed loads initially?


Solution

  • Simon: solution I previously proposed here works fine with reverse layout without any modification. The only thing I'd add for reverse layout is to scroll automatically to first item when you show it first time but that's up to you. Now getting back to issue you have. You mentioned that when you scroll nothing happens. so my guess is that you initialize your recylcer view in a wrong order. Make sure you do it like this

    mLayoutManager = new LinearLayoutManager(this);
    mLayoutManager.setReverseLayout(true);
    mLayoutManager.setStackFromEnd(true);
    
    mRecyclerView.setLayoutManager(mLayoutManager);
    mAdapter = new MyAdapter<>(myDataset, mRecyclerView);
    mRecyclerView.setAdapter(mAdapter);
    

    Note that layout manager gets instantiated first, then you set it and after that you provide adapter. Let me know if that was the case.

    Edit Just bringing up this from comment below:

    forget about what we have with onLoadMoreListener and all scrolling stuff just use standard RecyclerView wrapped in SwipeToRefreshLayout