通过反向无限滚动添加到ListView时保持滚动位置 [英] Maintain scroll position when adding to ListView with reverse endless-scrolling

查看:122
本文介绍了通过反向无限滚动添加到ListView时保持滚动位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建类似于Hangouts的类似于聊天的Android应用程序.为此,我使用带有stackFromBottom=truetranscriptMode="normal"的垂直ListView.

I am building a chat-like Android application, similar to Hangouts. For this purpose I am using a vertical ListView with stackFromBottom=true and transcriptMode="normal".

列表从较旧的消息(顶部)到较新的消息(底部)进行排序.在正常状态下,ListView滚动到底部,显示最年轻的消息.

The list is sorted from older messages (top) to younger messages (bottom). In normal state, the ListView is scrolled to the bottom, showing the youngest message.

一旦用户滚动到列表顶部,ListView将使用反向无限滚动适配器加载更多(较旧的)消息.加载较旧的消息后,它们将被添加到列表的顶部.

The ListView uses a reverse endless-scroll adapter to load more (older) messages once the user scrolls to the top of the list. Once older messages are loaded, they are added to the top of the list.

所需的行为是,将较旧的消息添加到列表视图的顶部时,ListView保持其滚动位置到列表的底部.也就是说,将较旧的消息添加到顶部时,滚动视图应显示与添加较旧的消息之前显示的消息相同的消息.

The desired behavior is that the ListView maintains its scroll-position to the bottom of the list, when older messages are added to the top of it. That is, when older messages are added to the top, the scroll-view should show the same messages that were shown before adding the older messages.

不幸的是,这不起作用. ListView不会将滚动位置保持在底部,而是将滚动位置保持在列表的顶部.也就是说,在将较旧的邮件添加到列表后,该列表将显示最顶部(即最旧)的邮件.

Unfortunately, this does not work. Instead of maintaining the scroll-position to the bottom, the ListView maintains the scroll-position to the top of the list. That is, after adding older messages to the list, the list shows the top-most (i.e oldest) messages.

在将新项目添加到ListView的顶部时,是否有一种简单的方法告诉ListView使其滚动位置保持在底部而不是顶部?

Is there an easy way to tell the ListView to maintain its scroll-position to the bottom, instead of the top, when adding new items to the top of it?

更新

出于演示目的,我尽可能地减少了用例和代码.下面的示例创建一个简单的字符串数组列表.单击一个项目将在列表顶部添加另一个项目.长按一个项目将在列表底部添加另一个项目.

For demonstration purposes, I have minimized the use-case and code as much as possible. The following example creates a simple string array list. Clicking on an item will add another item at the top of the list. Long-Clicking on an item will add another item at the bottom of the list.

在列表的底部添加项目(长按)时,一切正常.如果将项目添加到列表顶部(单击一下即可),则有3种情况:

Everything works fine when adding items at the bottom of the list (long-click). When adding items at the top of the list (simple click), then there are 3 cases:

  • 如果列表滚动到底部,则一切正常.将项目添加到顶部之后,列表仍会滚动到底部.
  • 如果列表未滚动到底部(也不滚动到顶部),则列表将保持其y滚动位置(从顶部开始).这使列表看起来像跳"上一个项目.在这种情况下,我希望列表不跳起来",即我希望它从底部开始保持其y滚动位置.
  • 如果列表滚动到顶部,则会发生与情况2相同的情况.首选行为与情况2相同.

(实际上,后两种情况是相同的.我将它们分开是因为在第2种情况下可以更好地证明问题.)

(The last 2 cases are in fact the same. I separated them because the problem can be better demonstrated in case 2.)

代码

public class MyListActivity extends Activity {
  int topIndex = 1;

  int bottomIndex = 20;

  protected final void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_list_activity);

    final ListView list = (ListView) findViewById(R.id.list);
    list.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
    list.setStackFromBottom(true);

    final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1);
    for (int i = topIndex; i <= bottomIndex; i++) {
      adapter.add(Integer.toString(i));
    }
    list.setAdapter(adapter);

    list.setOnItemClickListener(new OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        adapter.insert(Integer.toString(--topIndex), 0);
      }
    });

    list.setOnItemLongClickListener(new OnItemLongClickListener() {
      @Override
      public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        adapter.add(Integer.toString(++bottomIndex));
        return true;
      }
    });
  }
}

推荐答案

我已经弄清楚了.无论您在哪里获取新数据,在更改适配器中的数据之前,我都会调用以下命令:

I have figured this out. Wherever it is that you are getting new data I call the following before changing data in the adapter:

int firstVisibleItem = list.getFirstVisiblePosition();
int oldCount = adapter.getCount();
View view = list.getChildAt(0);
int pos = (view == null ? 0 :  view.getBottom());

然后我打电话给

adapter.setData(data);

list.setSelectionFromTop(firstVisibleItem + adapter.getCount() - oldCount + 1, pos);

这篇关于通过反向无限滚动添加到ListView时保持滚动位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆