前言
有时候我们需要记录和恢复ListView的滑动位置,网上给出大体的解决方案有2种。
- 记录上次滑动的坐标,恢复的时候直接
scrollTo
- 记录listView显示在屏幕上的第一个item的位置,然后利用
setSelection
恢复
我们分别来探讨一下这两种方案。
1、记录上次滑动的坐标,恢复的时候直接scrollTo
网上的步骤是通过监听ListView的滑动,在他停止滑动时通过listView.getScrollY();获取他的滑动坐标,然后再用scrollTo去恢复。
这样存在的问题是,getScrollY()永远为0,scrollTo会出现后面没有刷新的内容(一片空白)。
2、记录listView显示在屏幕上的第一个item的位置
用getFirstVisiblePosition
来记录和恢复可以避免方案1的各种问题,但是,他无法精确的恢复原来的位置,只是回滚到以getFirstVisiblePosition的View的起始位置。
我的解决方案
首先一要能精确回滚,二要能避免回滚后出现的一片空白。
所以只能放弃方案2,完善方案1,解决要点在于:
正确获取getScrollY()的滑动坐标
public int getScrollY() {
View c = mListView.getChildAt(0);
if (c == null) {
return 0;
}
int firstVisiblePosition = mListView.getFirstVisiblePosition();
int top = c.getTop();
return -top + firstVisiblePosition * c.getHeight() ;
}
这里的实现思路比较简单,就是计算屏幕显示部分上面的高度,通过获取第一个view(显示的)的top坐标(负数),用这个绝对值加上他之前的高度和就可以算出滑动的y坐标。
正确的回滚
直接scrollTo明显是不行的,他会导致后面有一片空白,而且一滑动ListView会重新刷新一下界面有明显的卡顿。
因此,我们只能使用smoothScrollBy
的方法,短时间内平滑移动至记录的位置。
简单的通过smoothScrollBy
来恢复明显是不行的,我们需要通过post方法去实现。
mListView.post(new Runnable() {
@Override
public void run() {
mListView.smoothScrollBy(scrolledY, 0);
}
});
这样就可以正确的回滚之前记录的位置。
小结
以上是小弟在解决该问题的一个小小思路,写出来方便大家一起探讨交流。
最后附上代码(比较简陋):
/**
* 用于记录和恢复ListView的滑动位置
* Created by ONEWateR on 2015/10/16.
*/
public class ListViewRecord {
private ListView mListView;
private int scrolledY;
public ListViewRecord(ListView listView) {
mListView = listView;
}
/**
* 设置listView的滑动监听
*/
public void initEvent() {
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 不滚动时记录当前滚动到的位置
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
record();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
}
/**
* 记录位置
*/
public void record() {
scrolledY = getScrollY();
}
/**
* 获取ListView的ScrollY
* @return
*/
public int getScrollY() {
View c = mListView.getChildAt(0);
if (c == null) {
return 0;
}
int firstVisiblePosition = mListView.getFirstVisiblePosition();
int top = c.getTop();
return -top + firstVisiblePosition * c.getHeight() ;
}
/**
* 恢复位置
*/
public void restore() {
mListView.post(new Runnable() {
@Override
public void run() {
mListView.smoothScrollBy(scrolledY, 0);
}
});
}
}
使用方法:
初始化
ListViewRecord record = new ListViewRecord(listView);
record.initEvent();
恢复
record.restore();