ListView 更新后滚动到顶部

Posted

技术标签:

【中文标题】ListView 更新后滚动到顶部【英文标题】:ListView scrolls to top after updating it 【发布时间】:2018-02-24 16:35:32 【问题描述】:

我有一个 mChildEventListener 查询来自 Firebase Database 的前 n 个项目和另一个 mChildEventListener2(当用户向上滚动并单击 Load More 按钮时触发)查询对于接下来的 n 项,并将它们添加到 ChatMessagesList

当用户单击Load More 按钮时:ChatMessagesList 被更新,notifyDataSetChanged 被调用。 mMessageListView 已更新,但每次都会向下滚动到底部。由于 xml 属性,我解释了这种行为:android:transcriptMode="alwaysScroll"

当我删除transcriptMode="alwaysScroll" 并且用户按下Load More 按钮时,mMessageListView 这次滚动到顶部。

这些行为都不是我们想要的。我希望当用户按下按钮时,mMessageListView 将保持其滚动位置。 (原因很明显)

我尝试从新线程调用notifyDataSetChanged。没有结果。

我尝试使用listView.setSelectionFromTop(lastViewedPosition, topOffset);list.smoothScrollToPosition();,但都没有达到我想要的流畅体验。

mMessageListView更新后如何保持滚动位置?

这是代码:

private ChildEventListener mChildEventListener;
private ChildEventListener mChildEventListener2;

List<ChatMessage> ChatMessages = new ArrayList<>();

@Override
protected void onCreate(Bundle savedInstanceState) 
      ...
mMessageAdapter = new MessageAdapter(this, R.layout.item_message_sent, ChatMessages);
mMessageListView.setAdapter(mMessageAdapter);

 mChildEventListener = new ChildEventListener() 
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) 
                if(i == 0) 
                    current_last_key = dataSnapshot.getKey();
                
                else 
                    ChatMessage chatMessage = dataSnapshot.getValue(ChatMessage.class);
                    mMessageAdapter.add(chatMessage);
                
                i++;
            
          ...
        ;
        Query messagesQuery =  mDatabaseReference.child("chat_messages").
                child(chatId).limitToLast(25);
        messagesQuery.addChildEventListener(mChildEventListener);
          ...
   

 @Override
public void onClick(View v) 
    j = 0;
    mChildEventListener2 = new ChildEventListener() 
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) 
            if(!dataSnapshot.getKey().equals(current_last_key)) 
                if (j == 0) 
                    current_last_key = dataSnapshot.getKey();
                
                else 
                    ChatMessage chatMessage = dataSnapshot.getValue(ChatMessage.class);
                    ChatMessages.add(j- 1, chatMessage);
                

            
            else
            
                ChatMessage chatMessage = dataSnapshot.getValue(ChatMessage.class);
                ChatMessages.add(0 , chatMessage);
                loadMoreTextView.setVisibility(View.GONE);
            
            mMessageAdapter.notifyDataSetChanged();
            j++;
        

        ...        ;
    Query query = mDatabaseReference.child("chat_messages").
            child(chatId).orderByKey().endAt(current_last_key).limitToLast(10);
    query.addChildEventListener(mChildEventListener2);

【问题讨论】:

【参考方案1】:
notifyDataSetChanged()

通知附加的观察者底层数据已更改,任何反映数据集的视图都应自行刷新。

尝试更新时是否再次调用“onCreate()”

【讨论】:

我没有看到相关性。请详细说明【参考方案2】:

FirebaseUI lib 为您处理所有这些并简化您的代码。 顺便说一句,您可以使用 mAdapter.notifyItemInserted(ChatMessages.size() - 1);mMessageAdapter.notifyItemRangeInserted(ChatMessages.size() - 1, ChatMessages.size() - 1 + numberOfItemsBeingInserted); 并进行其他必要的更改以使其正常工作,而不是使用 mMessageAdapter.notifyDataSetChanged();

【讨论】:

你的意思是 FirebaseUI 库处理数据分页? 是的!只需使用FirebaseIndexRecyclerAdapter(Class&lt;T&gt; modelClass, @LayoutRes int modelLayout, Class&lt;VH&gt; viewHolderClass, Query keyQuery, DatabaseReference dataRef) 构造函数而不是FirebaseRecyclerAdapter&lt;Food, FoodCardViewHolder&gt;( Food.class, R.layout.card_view_food, FoodCardViewHolder.class, foodInfoRef) 不过,使用 FirebaseIndexRecyclerAdapter 需要我索引我的 ChatMessages ,这是我避免的事情。我已经对我的数据进行了分页,我只是遇到了ListView 的问题

以上是关于ListView 更新后滚动到顶部的主要内容,如果未能解决你的问题,请参考以下文章

Listview在颤动中强制滚动到顶部

android listview如何按时加滚动到顶部?

Flutter ListView.builder在滚动时结结巴巴并跳到顶部[重复]

解决RecyclerView&ListView滚动到顶部或者底部边界出现阴影问题

Flutter ListView 跳转到顶部

Flutter:ListView里面的CheckboxListTile跳转到顶部