1. 程式人生 > >android 打造真正的無限迴圈viewpager

android 打造真正的無限迴圈viewpager

前言

目前,無限迴圈的viewpager有兩種實現方式:
1. 使adapter的getCount()返回Integer.MAX_VALUE,再在初始化時設定當前頁面為第幾百幾千頁(如:ViewPager.setCurrentItem(100*data.size));
2. 通過監聽viewpager的滑動來設定頁面。如當前有資料123,則設定頁面為31231,當頁面滑動到第一個3時,設定當前頁面為第二個3,那麼左右都可以滑動,當其滑動到第二個1時同理。

我們的實現方法

上述第一種實現方法網上已經有很多教程,大家可以自行去網上搜索,這裡就不再重複。

我們要採用的是第二種實現方法,看到這裡,有些試過的同學估計就要說了:『這個我早就試過了,當滑動到第一頁和最後一頁的時候會出現跳動的現象,太不友好了,博主真是XX』大兄弟你先別急,既然我知道這個問題,那麼必定是解決了這個不友好的問題才寫這篇部落格的。

先來看看效果


首先,我們還是先來介紹一下這個思路給沒有了解過的同學。

其實這個思路很簡單:
1. 新增最後一條資料到第一條,新增第一條資料到最後一條;
2. 設定監聽器;
3. 設定初始化時設定當前頁面為第二頁

我們知道使用這個思路會出現一個問題,就是:當滑動到第一頁和最後一頁時,會出現不友好的跳轉。那麼出現這個問題的原因是什麼呢?通過在onPageSelected(int position)函式中列印log資訊,我們發現這個函式在viewpager滑動動畫還沒結束的時候就已經被呼叫了,所以在這裡呼叫setCurrentItem方法會強制取消當前正在進行的動畫並跳轉。

那麼相應的,我們可以想到解決方法:
1. 在onPageSelected(int position)方法中記錄被選中的頁面;
2. 在onPageScrollStateChanged(int state)判斷當前動畫是否結束,當動畫結束時呼叫setCurrentItem方法跳轉頁面。

是不是很簡單?

一個介面卡搞定,我們直接來看下程式碼:

public abstract class LoopVPAdapter<T> extends PagerAdapter implements ViewPager.OnPageChangeListener{

//    當前頁面
    private
int currentPosition = 0; protected Context mContext; protected ArrayList<View> views; protected ViewPager mViewPager; public LoopVPAdapter(Context context, ArrayList<T> datas, ViewPager viewPager) { mContext = context; views = new ArrayList<>(); // 如果資料大於一條 if(datas.size() > 1) { // 新增最後一頁到第一頁 datas.add(0,datas.get(datas.size()-1)); // 新增第一頁(經過上行的新增已經是第二頁了)到最後一頁 datas.add(datas.get(1)); } for (T data:datas) { views.add(getItemView(data)); } mViewPager = viewPager; viewPager.setAdapter(this); viewPager.addOnPageChangeListener(this); viewPager.setCurrentItem(1,false); } @Override public int getCount() { return views.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(views.get(position)); return views.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(views.get(position)); } protected abstract View getItemView(T data); @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { currentPosition = position; } @Override public void onPageScrollStateChanged(int state) { // 若viewpager滑動未停止,直接返回 if (state != ViewPager.SCROLL_STATE_IDLE) return; // 若當前為第一張,設定頁面為倒數第二張 if (currentPosition == 0) { mViewPager.setCurrentItem(views.size()-2,false); } else if (currentPosition == views.size()-1) { // 若當前為倒數第一張,設定頁面為第二張 mViewPager.setCurrentItem(1,false); } } }

可以看到,我們將這個介面卡寫成抽象類,當你需要使用的時候,只需要繼承這個類,並實現getItemView方法,就可以直接使用啦~~是不是很方便?

  • 在建構函式中,判斷當資料大於一條時,新增第一頁和最後一頁,設定監聽器,設定當前頁面為第二頁(即實際中的第一頁)。
  • 在onPageSelected(int position)方法中記錄當前頁面,在onPageScrollStateChanged(int state)方法中跳轉頁面。

關鍵程式碼:

    @Override
    public void onPageSelected(int position) {
        currentPosition = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {
//        若viewpager滑動未停止,直接返回
        if (state != ViewPager.SCROLL_STATE_IDLE) return;
//        若當前為第一張,設定頁面為倒數第二張
        if (currentPosition == 0) {
            mViewPager.setCurrentItem(imageViews.size()-2,false);
        } else if (currentPosition == imageViews.size()-1) {
//        若當前為倒數第一張,設定頁面為第二張
            mViewPager.setCurrentItem(1,false);
        }
    }

使用

首先,繼承這個介面卡:

public class ImgAdapter extends LoopVPAdapter<String> {

    public ImgAdapter(Context context, ArrayList<String> datas, ViewPager viewPager) {
        super(context, datas, viewPager);
    }

    private ViewGroup.LayoutParams layoutParams;

    @Override
    protected View getItemView(String data) {
        if (layoutParams == null) {
            layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        }
        ImageView imageView = new ImageView(mContext);
        imageView.setLayoutParams(layoutParams);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        ImageUtils.loadImage(mContext, data, imageView);
        return imageView;
    }


}

然後,直接使用:

vp = (ViewPager) findViewById(R.id.vp);

urls.add("http://seopic.699pic.com/photo/00005/5186.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50010/0719.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50009/9449.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50002/5923.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50001/9330.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50009/9191.jpg_wh1200.jpg");

loopVPAdapter = new ImgAdapter(this,urls,vp);

使用方法比較簡單,這裡就不再累贅了。