简体   繁体   中英

Keep recyclerView at bottom when already at bottom and new item is added

I am creating a chat app. I am attempting to make all new messages appear at the bottom of the chat app when the current lowest item in the list is visible on screen, but not when the user is scrolled up (like most chat apps). As of right now, I have gotten this to work when there is still unused space on screen, but when the RecyclerView has too many views to fit, it begins placing new messages off screen to the bottom. Here is my method that creates the RecyclerView:

private void initRecyclerView() {


    mRecyclerView = findViewById(R.id.chatRecyclerView);
    mAdapter = new ChatRecyclerViewAdapter(this, mMessages, mUsernames, mRoomID, mDatabaseReference);
    mRecyclerView.setAdapter(mAdapter);
    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    linearLayoutManager.setStackFromEnd(true);
    RecyclerView.AdapterDataObserver observer = new RecyclerView.AdapterDataObserver() {
        @Override
        public void onChanged() {
            super.onChanged();

            if(linearLayoutManager.findLastVisibleItemPosition()==(mAdapter.getItemCount()-1)){
                mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount()-1);
            }
        }
    };
    mAdapter.registerAdapterDataObserver(observer);
    mRecyclerView.setLayoutManager(linearLayoutManager);

I ended up adding a check to see if the RecyclerView was at bottom and plugging that boolean into the AdapterDataObserver. I also made the mistake of using onChanged method of the observer instead of onItemRangeInserted, which apparently is required to complement notifyItemInserted in the RecyclerViewAdapter.

Here is my working code for a RecyclerView that automatically places new messages at the bottom if the user is at the bottom:

 private void initRecyclerView() {


    //initializes and sets adapter 


    mRecyclerView = findViewById(R.id.chatRecyclerView);
    mAdapter = new ChatRecyclerViewAdapter(this, mMessages, mUsernames, mRoomID, mDatabaseReference);
    mRecyclerView.setAdapter(mAdapter);

    //Creates layout manager and makes it feed new RecyclerView views from the bottom


    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    linearLayoutManager.setStackFromEnd(true);

    //Makes RecyclerView scroll to bottom when notifyItemInserted is called from adapter and RecyclerView is already at bottom

    RecyclerView.AdapterDataObserver observer = new RecyclerView.AdapterDataObserver() {
        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            super.onItemRangeInserted(positionStart, itemCount);


            if (isAtBottom) {
                mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
            } else {
            }
        }
    };

    //Adds logic to see if RecyclerView is at bottom or not

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (!recyclerView.canScrollVertically(1)) {
                isAtBottom = true;
            } else {
                isAtBottom = false;
            }
        }
    });

    //Assigns observer to adapter and LayoutManager to RecyclerView

    mAdapter.registerAdapterDataObserver(observer);
    mRecyclerView.setLayoutManager(linearLayoutManager);

}

mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount()-1); // remove this line.

and use this:

mAdapter.notifyItemRangeInserted(mAdapter.getItemCount(), list.size() - 1);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM