需求:
通過左右滑動刷新ViewPager的內容,要求往右前進,往左後退,除非遇到數據兩個端點否則不會間斷。
記錄一下我的處理過程,前後一共試用了4種方法:
方法一:ViewPager(10個page)
左右滑動處理:ViewPager中添加10個page,都是一個Fragment的複用,當滑動到最後一個界面時,跳轉到第一個page。實現循環滑動。
數據處理:
內存常駐10組數據。
第一次加載:初次加載10條數據,分別佈局到10個page上。
更新數據:每當向右滑動滑動到第10個page時,自動加載新的一組數據。每當向左滑動到第1個page時,加載一組新的數據。
當然,加載的數據可以從網上下載或者從本地數據表或文件加載。
思路介紹:
1.10張page的ViewPage只用在首尾加載數據,中間可以保證流暢滑動加載。
2.使用setCurrentItem();進行跳轉,實現循環滑動的效果。即只要有數據,向左向右可以無限拖動。
3,ViewPager滑動時的默認動畫是可以看到下一張的縮影的,而我們的數據已經佈局到每一個page上了,因此縮影上有數據。
出現的bug:
1.使用setCurrentItem();從最後一張跳到第一張時,不是一下跳到的,而是遍歷了從0-9張,可以使用下面的代碼來遮蓋這個效果,優化動畫:
//控制跳轉速度
public class FixedSpeedScroller extends Scroller {
private int mDuration = 0;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
@SuppressLint("NewApi")
public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, mDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
super.startScroll(startX, startY, dx, dy, mDuration);
}
}
//* 設置ViewPager的滑動速度
// *
// * */
private void setViewPagerScrollSpeed( ){
try {
Field mScroller = null;
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller( vp.getContext( ) );
mScroller.set( vp, scroller);
}catch(NoSuchFieldException e){
}catch (IllegalArgumentException e){
}catch (IllegalAccessException e){
}
}
2.由於是控制在前進或者退後的最後一張加載數據:即向左滑動,index+1,在第10張時更新數據;向右滑動,index-1,在第1張時更新數據。
但是如果你是index+1 到達最後一張,更新了下一組的數據(第2組 10-19),但是這時又往回拖動,希望還是顯示的第一組(0-9),就會發現顯示的是內存中剛加載的第二組(10-19)。同樣,在後退時也存在這樣一個bug。
3.10個page太多,佔用緩存。
方法二:ViewPager(3個page)
這時請教了羣裏的少年們得到的方法,謝謝。
使用了3個page的ViewPager,複用同一個Fragment。
左右滑動:
雖然使用了3個page的ViewPager,用戶看到的始終是第2個即中間的那個page。
當向左滑動,本來會跳到第3個page,使用setCurrentItem(1);跳回去。當向右滑動,本來會轉到第1個page,使用setCurrentItem(1);跳回去。
數據處理:
在使用了setCurrentItem(1);方法後更新數據。
思路:
1.是用戶看到的始終是第2個page,這樣解決了循環滑動的問題。
bug:
1.滑動page時看到的下一張的縮影是空白的。
2,內存中如果放置一組數據,還是無法預判加載一組新數據後用戶的操作。
方法三:ViewPager + GestureDetector
這時我想利用Gesture是否可以通過用戶的手勢事先預判用戶的滑動方向呢?這樣根據手勢來決定加載哪一組數據進入內存。
我在方法二的基礎上使用了GestureDetector,這時候出現了手勢事件處理的衝突問題
Viewpager是子控件, GestureDetector是綁定在父控件上的,改來改去,有時候只有ViewPager拿到手勢事件,有時候只有父控件拿到手勢事件。
突然我想到,既然能通過手勢來判斷左右動作,爲什麼不跳過ViewPager這個梗呢?只使用一個佈局,每次通過手勢判斷更新數據?
方法四: GestureDetector
只使用一個GestureDetector,通過手勢判斷前進或者後退。
但是數據處理上,一次加載10組數據進內存的辦法我放棄了。因爲即使使用手勢判斷,還是有bug,比如說現在顯示的10個數據中的組後一組,手勢判斷知道要前進,那麼會加載新的10個數據進內存,這時候如果再後退,會又加載10條舊的數據進內存。
因此我在數據處理上將數據放在SQLite表中,每次手勢判斷到向左或向右,就去數據表中加載對應的一條數據出來更新佈局。實驗證明,從數據表中select一條數據,然後即使根據數據再去sd卡上讀一張圖片,然後將文字和圖片佈局到界面上,效果還是不錯的。現在的手機cpu完全可以應對。
在程序中記錄當前的信息編號index以及本地表中最大的信息編號maxindex,然後在合適的時機下載若干組數據到本地存入SQLite數據表,這樣的話,每次滑動後臺執行的
動作就是讀表然後佈局。
四種方法中方法四是我現在採用的,當然不一定是最好的處理辦法。
寫的比較亂,希望對大家有所啓發,看不清楚可以在評論中指出,當然如果你有更好的辦法請分享給我!