1

I have a RecyclerView which im using to display messages, in a text app type way. By that I mean, new messages added to the RecyclerView should appear on the bottom.

Currently, im using .setStackFromEnd(true) on my LinearLayoutManager to make messages appear starting from the bottom:

layMng = new LinearLayoutManager(this);
layMng.setStackFromEnd(true);

mRecyclerView.setLayoutManager(layMng);
mRecyclerView.setAdapter(mAdapter);

What happens is, when enough messages are received and the list of messages is about to overflow past the top of the screen, it stops always showing the new messages at the bottom. I have to scroll down manually to see the new additions.

How can I get it to either always have the newest message be viewable or have the RecyclerView scroll down when a new item is received?

I tried various methods on my layout manager like .scrollToPosition() and .scrollToPositionWithOffset() but none of the suggestions i've seen so far have worked. A few of the top StackOverflow questions on the issue have top answers that dont even solve the original question..

So how is this done?

Orbit
  • 2,985
  • 9
  • 49
  • 106

4 Answers4

1

Please check layout_height. It should be android:layout_height="match_parent"

Run smoothScrollToPosition in UI thread

code snippet from my code

            <android.support.v7.widget.RecyclerView
                android:id="@+id/topic_screen_list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginBottom="18dp"

                />

//here topicScreenList is referencing my Recylerview: //-messageAdapter: referencing adpapter object

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {

    LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
    layoutManager.setStackFromEnd(true);
    topicScreenList.setLayoutManager(layoutManager);
    topicScreenList.setAdapter(messageAdapter);
}

after getting any new messages, following code gets called from backend service

-Here MessageItem is referencing new Message item consumed by adapter

@Override
public void onNewMessage(final MessageItem messageItem) {
    if (getActivity() != null) {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {                  
               messageAdapter.addMessageToEnd(messageItem);

       topicScreenList.smoothScrollToPosition(messageAdapter.getItemCount());

            }
        });
    }
}


//code from my Adapter  
public void addMessageToEnd(MessageItem messageItem) {
    messageItems.add(messageItem);
    notifyItemInserted(messageItems.size() -1);
}
jee
  • 524
  • 4
  • 7
0

Try this, Am also developing a chat application, and it works perfectly for me

    mRecyclerView.setAdapter(adaptorChat);
    mRecyclerView.setHasFixedSize(true);
    LinearLayoutManager llm = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
    llm.setStackFromEnd(true);
    mRecyclerView.setLayoutManager(llm);

XML

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/messages_list_sponsor"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/edit_compose_msg_container" />

    <LinearLayout
        android:id="@+id/edit_compose_msg_container"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:orientation="horizontal"
        android:padding="3dp">

        <EditText
            android:id="@+id/compose_edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginLeft="10dp"
            android:layout_marginStart="10dp"
            android:layout_weight="1"
            android:background="@drawable/white_edit_text_style"
            android:hint="@string/enter_message"
            android:inputType="textMultiLine"
            android:minHeight="50dp"
            android:paddingEnd="4dp"
            android:paddingLeft="6dp"
            android:paddingRight="4dp"
            android:paddingStart="6dp"
            android:singleLine="false"
            android:textColor="@color/black"
            android:textColorHint="@android:color/darker_gray" />

        <ImageView
            android:id="@+id/send_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="5"
            android:clickable="true"
            android:padding="15dp"
            android:rotation="-35"
            android:layout_marginBottom="5dp"
            android:src="@drawable/message_send" />
    </LinearLayout>
</RelativeLayout>
Sanoop Surendran
  • 3,484
  • 4
  • 28
  • 49
0

mRecyclerView.scrollToPosition(position); should work. It could be that it's trying to scroll before the position/adapter is updated. Try:

int delay = 500;

Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    public void run() {
        //scroll to bottom
        mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount());
    }
}, delay);
Sammy T
  • 1,924
  • 1
  • 13
  • 20
  • Doesn't seem to have any effect. – Orbit Jun 23 '16 at 06:14
  • Can you edit your original post with code showing where you're calling it from? – Sammy T Jun 23 '16 at 06:20
  • On mobile atm but I was calling the code you posted in my Activitys onCreate(), after all the RV and adapter setup was done. – Orbit Jun 23 '16 at 06:30
  • If it's fully loaded, it should work in the `onCreate` but it won't help you when adding a view. You need to make sure to call it after the adapter is updated. – Sammy T Jun 23 '16 at 06:37
  • Well thats how I initially tried it with my own code, I was doing adapter.add(object) and then doing the smooth scrolling stuff. Will try your code using a runnable and report back later. – Orbit Jun 23 '16 at 16:33
  • Yeah it should be triggered by the add and called after `mAdapter.notifyDataSetChanged();` – Sammy T Jun 23 '16 at 17:24
  • Hmm does smoothScrollToPosition require a custom layout manager? The docs mention that you need to override RecyclerView.LayoutManager.smoothScrollToPosition to enable it to work, but it seems to be working just calling `mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount());`. Any ideas why? – Orbit Jun 24 '16 at 02:48
  • Well I've never used the Override but, from what I can tell, using `.scrollToPosition()` and `.smoothScrollToPosition()` are more or less the same unless you want to control the smooth scroll motion. So no, if you want to use the default scroll. And yes, if you want to calculate the scroll yourself. – Sammy T Jun 24 '16 at 03:37
0

if you have set mRecyclerView.setNestedScrollingEnabled(false) then remove this.

Gundu Bandgar
  • 2,593
  • 1
  • 17
  • 21