Android ViewPager動態向前向後加載數據,自定義viewPager滑動速度

來自: http://hiqianjin.com/blog/474


update 8/22 這個文章過時了,關於viewPager動態加載的請看我另一篇文章,這個文章中調整viewpager的滑動速度的代碼還是可行的,關於動態加載,請看:http://hiqianjin.com/blog/516

最近用到一個效果,先有一個數據列表,然後,從這個列表中的任意一個位置進去,然後,點擊“上一條”,“下一條”進行數據加載,我用了viewPager進行加載,爲了使前後加載都有動畫效果,且viewPager加載到一定數量的數據後就刪除一些前後的數據(向前加載的時候就不斷刪後面的數據,向後反之)。

在viewPagerAdapter中,數據用了arrayList來封裝,當向前的時候,我在arrayList的0位置,也就是最前面加載一條數據,然後再讓adapter.notifyDataSetChange(),這樣數據就加載到裏面去了,關鍵是,當你處於viewPager index=0的時候,向前加載一條數據,然後,viewPager.setCurrentIndex(currenIndex – 1);目前,CurrenIndex = 0 ,-1後=-1,這樣是可以移動到向前加載的那一頁的,但是沒有滑動的效果,爲了讓它用效果,用了以下方法,先把viewPager的頁面移到加載後的第2頁,也就是加載前的第一頁,這次移動不要用動畫,第二次移動,用上動畫,在當前這個第二頁向前移動:

1 //這兒是關鍵,要不沒有跳轉效果 這是一次加載兩條數據的情況
2 vp.setCurrentItem(index+loadDataCount,false);
3 vp.setCurrentItem(index+loadDataCount - 1,true);

上面是向前加載的,麻煩一點,向後加載就簡單了,直接在arrayList里加載一條數據,然後:

1 //index = vp.getCurrentItem();
2 vp.setCurrentItem(index+loadDataCount,false);

主要的思路就是:當viewPager向前加載到快要到index=0的時候就去加載幾條數據,要麼到index=0的時候再去加載也行,向後一樣的道理,關鍵是移動的動畫處理。

—————————————————————————————————————————————–

DEMO完成後,一次加載多頁又不適用於我現有的項目,我又做成了viewPager中只會存在一條數據,當每次加載完,滑動到下一條數據後,就馬上把上一條刪掉,這下代碼就簡單了,大概如下:
向前加載:

01 //init your DataBean
02 list.add(0,yourDataBean)
03  
04 viewPagerAdapter.notifyDataSetChanged();
05 viewPager.setCurrentItem(index+1,false);
06 viewPager.setCurrentItem(index,true);
07 new Handler().postDelayed(new Runnable() {
08   @Override
09   public void run() {
10     pagerViews.remove(pagerViews.size()-1);
11     viewPagerAdapter.notifyDataSetChanged();
12   }
13 },500);

向後加載:

01 //init your DataBean
02 list.add(yourDataBean);
03 viewPagerAdapter.notifyDataSetChanged();
04 viewPager.setCurrentItem(index+1,true);
05 new Handler().postDelayed(new Runnable() {
06   @Override
07   public void run() {
08     pagerViews.remove(0);
09     viewPagerAdapter.notifyDataSetChanged();
10   }
11 },500);

這兒延遲500毫秒是因爲我的viewPager的滑動時間我自定義爲了400毫秒,如何自定義viewPager的滑動速度如下:
新建一個滑動處理類

01 import android.content.Context;
02 import android.view.animation.Interpolator;
03 import android.widget.Scroller;
04  
05 public class FixedSpeedScroller extends Scroller {
06  
07     private int mDuration = 2000;
08  
09     public FixedSpeedScroller(Context context) {
10         super(context);
11     }
12  
13     public FixedSpeedScroller(Context context, Interpolator interpolator) {
14         super(context, interpolator);
15     }
16  
17     @Override
18     public void startScroll(int startX, int startY, int dx, int dy, intduration) {
19         // Ignore received duration, use fixed one instead
20         super.startScroll(startX, startY, dx, dy, mDuration);
21     }
22  
23     @Override
24     public void startScroll(int startX, int startY, int dx, int dy) {
25         // Ignore received duration, use fixed one instead
26         super.startScroll(startX, startY, dx, dy, mDuration);
27     }
28  
29     public void setmDuration(int time) {
30         mDuration = time;
31     }
32  
33     public int getmDuration() {
34         return mDuration;
35     }
36 }

然後在你用到viewPager的地方用JAVA的反射來調整viewPager的滑動速度:

01 // use reflect change duration
02       try {
03         Field mField = ViewPager.class.getDeclaredField("mScroller");
04         mField.setAccessible(true);
05         FixedSpeedScroller mScroller =
06             new FixedSpeedScroller(viewPager.getContext(), newAccelerateInterpolator());
07         // 可以用setDuration的方式調整速率
08         mScroller.setmDuration(400);
09         mField.set(viewPager, mScroller);
10       catch (Exception e) {
11         e.printStackTrace();
12       }

主要是滑動效果的處理,折騰了好久,有還是不明白的同學可以email我。




以前寫過一次這個文章,在這兒,直到上週末,做一個圖片應用的時候,發現以前出現了方向性錯誤,導致可能誤導了一些人,大家看到以前那篇文章的時候,估計沒有幾個人能看明白是怎麼回事兒,在動態向前向後加載的時候,有不少的小邏輯判斷,極容易出錯,而且不斷的設置setCurrentItem(),在臨界的時候,其實用了一個先把viewPager設置爲無動畫,跳轉一次位置,再設置viewPager有動畫,再次跳轉位置,模擬有動畫的效果,其實在這個操作過程中仔細看,能看出來page的變化的,效果不好。

好了,扯了這麼大一通,從上面一段就可以看出來以前寫得不簡單了,下面是新的思路,效果和邏輯都很簡單:

再來回顧一下這個功能的應用場景:有一個裝有很多條數據的一個list,這個list在listView中顯示出來了,現在滑動listView隨便到一個位置,點擊一個item進入數據的詳情頁,在這個詳情頁,我們用到了viewPager,讓它實現左右滑動的效果。

以前我也是在網上找的DEMO,大家通常的做法是,一進入詳情頁,就把每個頁面的view初始化出來,然後把這些view放在list裏面,傳給自己定義的viewPagerAdapter,這樣就出現滑動效果了。但是這樣就會出現一個問題,就是我的list太大,初始化出來的view頁面就會很多,比如說1000條數據,不可能全初始化出view來放list裏再傳給adapter吧,這樣八成OOM的,於是我就照着這個思路,先初始化一部分view,再不斷的滑動過程中,再初始化一部分,但是如果你是從數據列表的中間進入,向前滑動時不斷的初始化view添加進list,這樣viewPagerAdapter的大小就會發生變化,你的currentIndex就在不斷的變化。超級不好控制。

再回想一下我們平時做一些常見的adapter的做法,沒有在activity中把所有的item初始化出來,再傳給adapter,讓adapter做顯示吧,常用的做法是,在adapter裏再進行數據的封裝什麼的,在adapter中的getView()中進行操作,無論是自定義界面,還是填充數據。其實,viewPager的PagerAdapter也是同樣的思路。回想一下,其實就是基本的adapter的操作了,以前剛學習這個控件的時候被網上別人的demo誤導了。

01 public class DemoAdapter extends PagerAdapter {
02  
03   private Context context;
04   private ArrayList list;
05   private LayoutInflater inflater;
06  
07   public DemoAdapter (Context context, ArrayList list) {
08     this.list = list;
09     this.context = context;
10     inflater = LayoutInflater.from(context);
11  
12   }
13  
14   @Override
15   public void destroyItem(ViewGroup container, int position, Object object) {
16     ((ViewPager) container).removeView((View) object);
17   }
18  
19   @Override
20   public void finishUpdate(View container) {}
21  
22   @Override
23   public int getCount() {
24     return list != null ? list.size() : 0;
25   }
26  
27   @Override
28   public Object instantiateItem(ViewGroup view, int position) {
29  
30     UserBean bean = list.get(position);
31  
32     //自定義的view
33     View userLayout = inflater.inflate(R.layout.show_user_detail, view,false);
34     ImageView ivPhoto = (ImageView) userLayout.findViewById(R.id.user_photo);
35     TextView tvName = (TextView) userLayout.findViewById(R.id.user_name);
36  
37     //填充數據 
38     tvName.setText(bean.getUserName);
39  
40     ((ViewPager) view).addView(userLayout, 0);
41     return userLayout;
42   }
43  
44   @Override
45   public boolean isViewFromObject(View view, Object object) {
46     return view.equals(object);
47   }
48  
49   @Override
50   public void restoreState(Parcelable state, ClassLoader loader) {}
51  
52   @Override
53   public Parcelable saveState() {
54     return null;
55   }
56  
57   @Override
58   public void startUpdate(View container) {}
59 }

看完上面這段代碼是不是很簡單,還要注意一點就是,你在外面的listView從哪兒跳進viewPager的時候,要在viewPager設置完adapter的時候setCurretntIndex一下,就像下面這樣:

1 viewPager.setCurrentItem(intoPosition)

我還做了個簡單的DEMO放在Github上,超級簡單,其實就是跟平常用adapter一樣:地址 .


發佈了5 篇原創文章 · 獲贊 15 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章