20

我正在尝试使用RecyclerView创建聊天应用程序。我正在使用LinearLayoutManagerwith setReverseLayout(true)

当我一直滚动到底部(即数据集开始 = 最新消息)并将新消息插入数据集中时,该项目按预期显示在列表底部(视图向上滚动以腾出空间对于新项目)。

我遇到的问题是当我向上滚动查看旧消息时。当一条新消息插入到数据集的开头时,视图会向上滚动大约一个消息高度,即使该消息甚至没有呈现,因为它超出了视口的范围。

当视图滚动到底部时,如何保持滚动行为,但在滚动到旧消息时禁用它?

更新: 我还制作了一个小应用程序,重现了这个问题: https ://github.com/ehehhh/RecyclerViewProblem

更新 2:我也提交了对我所做的 repo 有效的修复。

相关代码(希望):

compile 'com.android.support:recyclerview-v7:24.2.0'

XML:

<android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:paddingBottom="8dp"
            android:paddingTop="8dp"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

RecyclerView初始化代码:

layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setScrollContainer(true);
recyclerView.setLayoutAnimation(null);
recyclerView.setItemAnimator(null);
adapter = new ChatAdapter(...);
recyclerView.setAdapter(adapter);

适配器

public class ChatAdapter extends RecyclerView.Adapter<ChatViewHolder> {

    private List<MessageWrapper> dataset;

    public ChatAdapter(List<MessageWrapper> dataset, ...) {
        this.dataset = dataset;
        setHasStableIds(true);
    }

    ...

    @Override
    public long getItemId(int position) {
        return dataset.get(position).getId();
    }

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

    public void datasetChanged(List<MessageWrapper> dataset) {
        this.dataset = dataset;
        notifyDataSetChanged();
    }
}

当向数据集中添加新项目时,我只需调用datasetChanged适配器中的方法。

4

2 回答 2

6

如果您知道可以使用已更改的项目,则在 Recycler 视图中使用 notifyDataSetChanged 是多余的

notifyItemInserted(position) 

在这种特殊情况下,有效的是

 notifyItemInserted(0);

或者

 notifyItemRangeInserted(positionStart, newItems.size() - 1)

这只会重新绑定此范围内的视图

检查 https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#notifyItemInserted(int)

于 2016-09-05T09:31:12.157 回答
0

我有一个类似的问题。我正在制作聊天应用程序,我的 RecyclerView 总是从顶部显示行,我希望它转到底部以显示最后插入的消息。这对我有用, recyclerView.scrollToPosition(messages.size()-1)添加到ChildEventListener

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private MessageAdapter mMessageAdapter;
    private List<Message> messages;

    private FirebaseDatabase mFirebaseDatabase;
    private DatabaseReference mMessagesDatabaseRef;

    ....


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mFirebaseDatabase = FirebaseDatabase.getInstance();
        mMessagesDatabaseRef = mFirebaseDatabase.getReference().child("messages");


        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);


        // Initialize message ListView and its adapter
        messages = new ArrayList<>();
        mMessageAdapter = new MessageAdapter(messages);



        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);

        recyclerView.setAdapter(mMessageAdapter);

       .....   

        mMessagesDatabaseRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {


                messages.add(dataSnapshot.getValue(Message.class));

                recyclerView.scrollToPosition(messages.size()-1);
                mMessageAdapter.notifyDataSetChanged();

            }

            ......


        });

    }



}
于 2017-08-09T23:16:53.987 回答