Add items to bottom of Recycler View

15,616

Solution 1

Try removing these two lines or setting them false

layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);

setStackFromEnd will set the view to show the last element, the layout direction will remain the same whereas setReverseLayout will change the order of the elements added by the Adapter.

Try using this to move your RecyclerView and EditText up when keyboard appears

<activity name="YourActivity"
          android:windowSoftInputMode="stateHidden|adjustResize">
          //stateHidden -> keyboard is hidden when you first open the activity
          //adjustResize -> this will adjust the layout resize option
 ...
</activity>  

in AndroidManifest.xml.

To hook the RecyclerView at top

    <android.support.v7.widget.RecyclerView
    android:id="@+id/messageRecyclerViewRep"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_below="@+id/linearLayout3"
    android:layout_marginLeft="36dp"
    android:scrollbars="vertical" />

To put the recyclerView at bottom first and push it up as the keyboard pops up.

 <LinearLayout
    android:id="@+id/recyclerContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/linearLayout3"
    android:layout_above="@+id/linearLayout"
    android:gravity="bottom">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/messageRecyclerViewRep"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="36dp"
        android:scrollbars="vertical" />
</LinearLayout>

To scroll the recyclerView to bottom when keyboard pops up i.e. when the recycler view's layout is changed ( You can do the same thing on Edit Text active or focused or clicked or something like that. I've done it on recycler view's layout change. )

   recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                if (bottom < oldBottom) {
                    recyclerView.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            recyclerView.smoothScrollToPosition(mAdapter.getItemCount());
                        }
                    }, 100);
                }
            }
        });

Solution 2

setReverseLayout(true) this will reverse the item traversal & layout order.The first item will come to end not view or content.

setStackFromEnd(true) this will fill the recycler list content starting from the bottom of the view.

Need to setStackFromEnd(true) not setReverseLayout(true)

And in XML Recyclerview height should be match_parent

Below i have given working code.

activity xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btnAdd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rcList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="true" />


</LinearLayout>

list item xml layout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="20dp"
    android:layout_marginRight="20dp"
    android:gravity="center_vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content" android:textSize="23sp"
        android:layout_height="wrap_content" android:textColor="#4a4883"
        android:text="Test Text" />
</FrameLayout>

Adapter class

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private static final String TAG = "CustomAdapter";

    private ArrayList<String> mDataSet;
    private int size = 0;


    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView textView;

        public ViewHolder(View v) {
            super(v);
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(TAG, "Element " + getAdapterPosition() + " clicked.");
                }
            });
            textView = (TextView) v.findViewById(R.id.textView);
        }

        public TextView getTextView() {
            return textView;
        }
    }


    public CustomAdapter(ArrayList<String> dataSet) {
        mDataSet = dataSet;
        if (mDataSet != null && !mDataSet.isEmpty()) {
            size = mDataSet.size();
        }
    }

    public void refreshData(String add) {
        if (!TextUtils.isEmpty(add)) {
            mDataSet.add(add);
            size = mDataSet.size();
            notifyDataSetChanged();

        }

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view.
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.list_item, viewGroup, false);

        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        Log.d(TAG, "Element " + position + " set.");

        viewHolder.getTextView().setText(mDataSet.get(position));
    }

    @Override
    public int getItemCount() {
        return size;
    }
}

Activity class

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    protected CustomAdapter mAdapter;
    protected LinearLayoutManager mLayoutManager;
    protected ArrayList<String> listString = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRecyclerView = (RecyclerView) findViewById(R.id.rcList);
        mLayoutManager = new LinearLayoutManager(this);
        mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        /**
         *setStackFromEnd true will fill the content(list item) from the bottom of the view
         */
        mLayoutManager.setStackFromEnd(true);
        mLayoutManager.setReverseLayout(true);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        findViewById(R.id.btnAdd).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int temp = mAdapter.getItemCount() + 1;
                mAdapter.refreshData("Test text " + temp);
                mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount());
            }
        });
        mAdapter = new CustomAdapter(listString);
        mRecyclerView.setAdapter(mAdapter);

    }
}

enter image description here

Solution 3

The simplest way to achieve this would be to load the elements into the Recyclerview in the reverse order to how they are entered in the Firebase Database.

@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
    Log.d(TAG, "Element " + position + " set.");
    viewHolder.getTextView().setText(mDataSet.get(getItemCount() - 1 -position));
}

What this would do is that the item which is inserted last will get displayed at bottom since you are loading the items from top. No need for any change in any of the XMLs or any other code.

I had same issues with Recylerview not resizing itself when the keyboard pops up and therefore I resorted to this method.

All the best!!

Solution 4

I have implemented and here is my Implementation using FirebaseRecyclerView you need to set this setStackFromEnd=true and setReverseLayout=true

my xml

Recycler View Holder

public class TestingFirebaseHolder extends RecyclerView.ViewHolder {

    private TextView mTextView;
    private TextView mTextView2;

    public TestingFirebaseHolder(View itemView) {
        super(itemView);
        mTextView = itemView.findViewById(R.id.textViewTesting);
        mTextView2 = itemView.findViewById(R.id.textViewTesting2);
    }

    public void setTextView(String text,String text2)
    {
        mTextView.setText(text);
        mTextView2.setText(text2);
    }
}

Testing Class

public class TestingUser {

    public String UserName;
    public String mUid;

    public TestingUser() {
    }

    public TestingUser(String userName, String uid) {
        UserName = userName;
        mUid = uid;
    }
}

Activity Code

private EditText mEditText;
private RecyclerView mRecyclerView;
private FirebaseRecyclerAdapter<TestingUser,TestingFirebaseHolder> mAdapter;
private FirebaseUser mUser;
private DatabaseReference mReference;

    mEditText = findViewById(R.id.testingEditText);
    mRecyclerView = findViewById(R.id.hello_rec);
    mUser = FirebaseAuth.getInstance().getCurrentUser();
    mReference = FirebaseDatabase.getInstance().getReference();
    LinearLayoutManager ll = new LinearLayoutManager(this);
    ll.setReverseLayout(true); // set this
    ll.setStackFromEnd(true); // set this
    mRecyclerView.setLayoutManager(ll);

    Query query = mReference.child("Testing").child(mUser.getUid()).orderByValue();



    mAdapter = new FirebaseRecyclerAdapter<TestingUser, TestingFirebaseHolder>(
            TestingUser.class,R.layout.testing_recycler_layout,TestingFirebaseHolder.class,query
    ) {
        @Override
        protected void populateViewHolder(TestingFirebaseHolder viewHolder, TestingUser model, int position) {

            viewHolder.setTextView(model.mUid,model.UserName);

        }
    };

    mRecyclerView.setAdapter(mAdapter);


public void buttonClick(View view) {

        if(!mEditText.getText().toString().isEmpty())
        {
            TestingUser user = new TestingUser("Salman",mEditText.getText().toString());
            mReference.child("Testing").child(mUser.getUid()).push().setValue(user);
            mEditText.setText("");
        }

    }

Result is link

Solution 5

Try this, it works for me.

mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.stackFromEnd(true)
mLinearLayoutManager.isSmoothScrollbarEnabled(true)
mMessageRecyclerView.setLayoutManager(mLinearLayoutManager);
Share:
15,616

Related videos on Youtube

Admin
Author by

Admin

Updated on September 14, 2022

Comments

  • Admin
    Admin over 1 year

    Code of the illustration:

    mLinearLayoutManager = new LinearLayoutManager(this);
    mLinearLayoutManager.setReverseLayout(true);
    mLinearLayoutManager.setStackFromEnd(true);
    mMessageRecyclerView.setLayoutManager(mLinearLayoutManager);
    

    See illustration here

    How can I add new items (in my case, messages) to the bottom of Recycler View and still keep the "gravity" of the view to the top?

    So, what works now is the following:

    • The gravity of the view is at the top. That's good! ✓

    What doesn't work:

    • New messages are added to the top of the view. That's bad × I want them to be added at the bottom of the view (after the previous message) like so: See here
  • Admin
    Admin over 6 years
    Thanks for your long answer. But, I am already using FirebaseRecyclerAdapter Here's a similar project that also uses FirebaseRecyclerAdapter: github.com/firebase/friendlychat-android/tree/master/android
  • Admin
    Admin over 6 years
    I don't who deleted the he previous comments but here's my XML file again: pastebin.com/XGrN5Dsj
  • Jonathan Doe
    Jonathan Doe over 6 years
    The bounty will be awarded once the asker's problem is resolved.
  • Admin
    Admin over 6 years
    The issue is still not fixed.
  • Admin
    Admin over 6 years
    I want when the soft keyboard pops up, the RecyclerView to pushed also.
  • Niraj Niroula
    Niraj Niroula over 6 years
    Did you tried the edited one. Man, why don't you experiment your xml! Just take your time.