在 Recycler View 底部添加项目

25

示例代码:

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

在这里查看插图

我该如何将新项(在我的情况下是消息)添加到 Recycler View 的底部,同时仍保持视图的“重力”在顶部?

目前,以下内容有效:

  • 视图的重力位于顶部。很好!✓

不起作用的是:

  • 新消息会添加到视图的顶部。那不好 × 我希望它们像下面这样添加到视图底部(在上一条消息之后): 请看这里

可能需要将您拥有的对象列表反转,再次传递给适配器并调用notifyDataSetChanged()。 - Ashish Kumar
@Gowthaman,你能否在回答中提供更多的上下文信息? - user8618899
@Ashish,你能在回答中提供更多细节吗? - user8618899
@Gowthaman,我不理解你的评论,请提供更多上下文。 - user8618899
@Gowthaman 我正在使用 FirebaseRecyclerAdapter<FriendlyMessage, MessageViewHolder> mFirebaseAdapter; - user8618899
显示剩余3条评论
5个回答

16

尝试删除这两行或将它们设置为false

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

setStackFromEnd方法将视图设置为显示最后一个元素,布局方向保持不变,而setReverseLayout方法将改变Adapter添加元素的顺序。

尝试使用这些方法在键盘出现时将你的RecyclerViewEditText向上移动。

<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>  

AndroidManifest.xml文件中。

将RecyclerView置于顶部。

    <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" />

首先将recyclerView放在底部,随着键盘的弹出将其向上推。

 <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>

当键盘弹出时,将recyclerView滚动到底部,即当recyclerView的布局更改时(您可以在编辑文本处处于活动状态、聚焦、单击或类似情况下执行相同的操作。我已在recyclerView的布局更改上完成了此操作。)

   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);
                }
            }
        });

我不知道是谁删除了之前的评论,但这是我的 XML 文件链接:https://pastebin.com/XGrN5Dsj - user8618899
RecyclerView 总是在顶部。 - Niraj Niroula
当键盘弹出时,RecyclerView的消息不会被推上去。 - user8618899
当键盘弹出时,最后一条消息是否会出现?所以,您希望recyclerView首先位于底部,但是当键盘弹出时,您希望将其推上去。是这样吗? - Niraj Niroula
是的,我想就是这样。现在,当键盘弹出时,最后的消息因为键盘覆盖而不可见。 - user8618899
显示剩余16条评论

6

setReverseLayout(true) 会反转项目遍历和布局顺序。第一个项目将出现在末尾而不是视图或内容。

setStackFromEnd(true) 会从视图底部开始填充回收站列表内容。

需要使用 setStackFromEnd(true) 而不是 setReverseLayout(true)

在 XML 中,Recyclerview 的高度应为 match_parent

下面是可工作的代码。

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>

列表项xml布局

<?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


谢谢您的长篇回答。但是,我已经在使用FirebaseRecyclerAdapter了。这里有一个类似的项目,也使用了FirebaseRecyclerAdapter:https://github.com/firebase/friendlychat-android/tree/master/android - user8618899

2
最简单的方法是将元素以与它们在Firebase数据库中输入的顺序相反的顺序加载到Recyclerview中。
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
    Log.d(TAG, "Element " + position + " set.");
    viewHolder.getTextView().setText(mDataSet.get(getItemCount() - 1 -position));
}

这样做的效果是,由于你从上往下加载项目,所以最后插入的项目会显示在底部。不需要对任何XML或其他代码进行任何更改。

我曾经遇到过Recylerview在键盘弹出时没有自适应大小的问题,因此我采用了这种方法。

祝一切顺利!


1
我已经实现了,这是使用FirebaseRecyclerView的我的具体实现。你需要设置 setStackFromEnd=truesetReverseLayout=true

我的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);
    }
}

测试类

public class TestingUser {

    public String UserName;
    public String mUid;

    public TestingUser() {
    }

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

活动代码
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("");
        }

    }

结果是: link

1
尝试这个,对我有效。
mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.stackFromEnd(true)
mLinearLayoutManager.isSmoothScrollbarEnabled(true)
mMessageRecyclerView.setLayoutManager(mLinearLayoutManager);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接