前言
有時候我們需要記錄和恢復(fù)ListView的滑動位置,網(wǎng)上給出大體的解決方案有2種。
- 記錄上次滑動的坐標(biāo),恢復(fù)的時候直接
scrollTo
- 記錄listView顯示在屏幕上的第一個item的位置,然后利用
setSelection
恢復(fù)
我們分別來探討一下這兩種方案。
1、記錄上次滑動的坐標(biāo),恢復(fù)的時候直接scrollTo
網(wǎng)上的步驟是通過監(jiān)聽ListView的滑動,在他停止滑動時通過listView.getScrollY();獲取他的滑動坐標(biāo),然后再用scrollTo去恢復(fù)。
這樣存在的問題是,getScrollY()永遠(yuǎn)為0,scrollTo會出現(xiàn)后面沒有刷新的內(nèi)容(一片空白)。
2、記錄listView顯示在屏幕上的第一個item的位置
用getFirstVisiblePosition
來記錄和恢復(fù)可以避免方案1的各種問題,但是,他無法精確的恢復(fù)原來的位置,只是回滾到以getFirstVisiblePosition的View的起始位置。
我的解決方案
首先一要能精確回滾,二要能避免回滾后出現(xiàn)的一片空白。
所以只能放棄方案2,完善方案1,解決要點(diǎn)在于:
正確獲取getScrollY()的滑動坐標(biāo)
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() ;
}
這里的實(shí)現(xiàn)思路比較簡單,就是計算屏幕顯示部分上面的高度,通過獲取第一個view(顯示的)的top坐標(biāo)(負(fù)數(shù)),用這個絕對值加上他之前的高度和就可以算出滑動的y坐標(biāo)。
正確的回滾
直接scrollTo明顯是不行的,他會導(dǎo)致后面有一片空白,而且一滑動ListView會重新刷新一下界面有明顯的卡頓。
因此,我們只能使用smoothScrollBy
的方法,短時間內(nèi)平滑移動至記錄的位置。
簡單的通過smoothScrollBy
來恢復(fù)明顯是不行的,我們需要通過post方法去實(shí)現(xiàn)。
mListView.post(new Runnable() {
@Override
public void run() {
mListView.smoothScrollBy(scrolledY, 0);
}
});
這樣就可以正確的回滾之前記錄的位置。
小結(jié)
以上是小弟在解決該問題的一個小小思路,寫出來方便大家一起探討交流。
最后附上代碼(比較簡陋):
/**
* 用于記錄和恢復(fù)ListView的滑動位置
* Created by ONEWateR on 2015/10/16.
*/
public class ListViewRecord {
private ListView mListView;
private int scrolledY;
public ListViewRecord(ListView listView) {
mListView = listView;
}
/**
* 設(shè)置listView的滑動監(jiān)聽
*/
public void initEvent() {
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 不滾動時記錄當(dāng)前滾動到的位置
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() ;
}
/**
* 恢復(fù)位置
*/
public void restore() {
mListView.post(new Runnable() {
@Override
public void run() {
mListView.smoothScrollBy(scrolledY, 0);
}
});
}
}
使用方法:
初始化
ListViewRecord record = new ListViewRecord(listView);
record.initEvent();
恢復(fù)
record.restore();