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.