我正在使用OnScrollListener在用户滚动到底部时动态地将项添加到ListView.在我将数据添加到适配器并调用notifyDataSetChanged后,ListView返回到顶部.理想情况下,我想保留ListView中的位置.关于我应该怎么做的任何想法?
我正在构建类似于Google Hangouts聊天界面的界面.新消息将添加到列表底部.向上滚动到列表顶部将触发先前消息历史记录的加载.当历史从网络进入时,这些消息将添加到列表的顶部,并且不应从触发负载时用户已停止的位置触发任何类型的滚动.换句话说,列表顶部显示"加载指示符":

然后将其替换为任何已加载的历史记录.

我完成了所有这些工作......除了一件我不得不诉诸于反思的事情.当向连接到ListView的适配器添加项目时,有很多问题和答案涉及仅保存和恢复滚动位置.我的问题是当我做类似以下的事情时(简化但应该是不言自明的):
public void addNewItems(List<Item> items) {
final int positionToSave = listView.getFirstVisiblePosition();
adapter.addAll(items);
listView.post(new Runnable() {
@Override
public void run() {
listView.setSelection(positionToSave);
}
});
}
Run Code Online (Sandbox Code Playgroud)
然后用户将看到的是快速闪烁到ListView的顶部,然后快速闪回到正确的位置.这个问题很明显,并且被很多人发现:setSelection()直到之后notifyDataSetChanged()重新开始并且不重要ListView.所以我们必须要有post()机会画画.但那看起来很糟糕.
我通过使用反射来"修复"它.我讨厌它.在其核心,就是我要完成的任务是重置的第一位置ListView,而无需通过抽奖周期的rigamarole下去,直到后,我给自己定的位置.要做到这一点,ListView有一个有用的领域:mFirstPosition.通过gawd,这正是我需要调整的!不幸的是,它是包私有的.还不幸的是,似乎没有任何方式以编程方式设置它或以任何不涉及无效循环的方式影响它...产生丑陋的行为.
因此,反映失败的后备:
try {
Field field = AdapterView.class.getDeclaredField("mFirstPosition");
field.setAccessible(true);
field.setInt(listView, positionToSave);
}
catch (Exception e) { // CATCH ALL THE EXCEPTIONS </meme>
e.printStackTrace();
listView.post(new Runnable() {
@Override
public void run() {
listView.setSelection(positionToSave);
}
}); …Run Code Online (Sandbox Code Playgroud) ArrayAdapter具有add(T object)在列表末尾添加对象的方法.有没有办法在列表的开头添加对象?
使用 ListView,我可以通过设置轻松实现自动滚动聊天视图:
android:transcriptMode="alwaysScroll"
Run Code Online (Sandbox Code Playgroud)
在它的 XML 中。RecyclerView 中是否有等价物?
http://developer.android.com/reference/android/widget/AbsListView.html#attr_android:transcriptMode