我正在构建类似聊天的Android应用程序,类似于环聊。为此,我使用了stackFromBottom=true
和transcriptMode="normal"
的垂直ListView。
列表从较旧的消息(顶部)到较年轻的消息(底部)排序。在正常状态下,ListView会滚动到底部,显示最年轻的消息。
一旦用户滚动到列表顶部,ListView就会使用反向无限滚动适配器来加载更多(较旧的)消息。加载旧邮件后,它们会添加到列表顶部。
当旧的消息添加到其顶部时,所需的行为是ListView将其滚动位置保持在列表的底部。也就是说,当较旧的消息添加到顶部时,滚动视图应显示在添加旧消息之前显示的相同消息。
不幸的是,这不起作用。而不是将滚动位置保持在底部, ListView将滚动位置保持在列表顶部。也就是说,在将较旧的消息添加到列表之后,该列表显示最顶层(即最旧的)消息。
在将新项目添加到顶部时,是否有一种简单的方法可以告诉ListView将其滚动位置保持在底部而不是顶部?
更新
出于演示目的,我尽可能地减少了用例和代码。以下示例创建一个简单的字符串数组列表。单击某个项目将在列表顶部添加另一个项目。长按单击某个项目将在列表底部添加另一个项目。
在列表底部添加项目时,一切正常(长按)。在列表顶部添加项目(简单点击)时,有3种情况:
(最后两个案例实际上是相同的。我把它们分开了,因为在案例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;
}
});
}
}
答案 0 :(得分:11)
我已经弄明白了。无论您在哪里获得新数据,我都会在更改适配器中的数据之前调用以下内容:
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);
答案 1 :(得分:2)
首先得到firstVisiblePosition(或者自上翻以来的最后一个。哟必须自己尝试检查),然后获得添加到List中的View的顶部,然后使用setSe; ectionFromTop()方法,您可以滚动到所需的位置。
代码:
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0); //or upside down (list.size - 1)
int top = (v == null) ? 0 : v.getTop(); //returns the top of the view its Y co-ordinates. [Doc][1]
mList.setSelectionFromTop(index, top);
答案 2 :(得分:0)
编辑以说明其他信息:
我想我找到了你的问题。我使用独立列表作为XML中的唯一视图来复制您描述的用例:
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
我通过将布局嵌套在父布局中来修复问题以遵循所需的用例:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</FrameLayout>
答案 3 :(得分:-2)
在适配器中插入记录后,您可以尝试使用
yourListView.setSelection(yourAdapter.getCount() - 1);