Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中級:實現ViewPager的無線自動循環

Android中級:實現ViewPager的無線自動循環

編輯:關於Android編程

無限自動循環 = 無限循環 + 自動循環
無限循環 = 無限向左循環 + 無限向右循環

這裡寫圖片描述
接下來我們通過demo一步步的實現無限向右循環–>無限向左循環–>自動循環

Demo中viewpager中放有5張圖片,我們可以向左向右滑動,但是
若當前頁是第一頁,則無法再向右滑動。
若當前頁是最後一頁,則無法再向左滑動。

一般情況:沒有循環,需手滑

activity_main.xml



    

MainActivity.java

public class MainActivity extends Activity {

    protected static final String tag = "MainActivity";
    private ViewPager viewpager;
    private List imageList = new ArrayList();
    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;
        initData();
        viewpager = (ViewPager) findViewById(R.id.viewpager);
        viewpager.setAdapter(new MyAdapter());
    }

    private void initData() {
        imageList.clear();
        ImageView iva = new ImageView(context);
        iva.setBackgroundResource(R.drawable.a);

        ImageView ivb = new ImageView(context);
        ivb.setBackgroundResource(R.drawable.b);

        ImageView ivc = new ImageView(context);
        ivc.setBackgroundResource(R.drawable.c);

        ImageView ivd = new ImageView(context);
        ivd.setBackgroundResource(R.drawable.d);

        ImageView ive = new ImageView(context);
        ive.setBackgroundResource(R.drawable.e);

        imageList.add(iva);
        imageList.add(ivb);
        imageList.add(ivc);
        imageList.add(ivd);
        imageList.add(ive);
    }

    public class MyAdapter extends PagerAdapter{
        //表示viewpager共存放了多少個頁面
        @Override
        public int getCount() {
            return imageList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(imageList.get(position));
            return imageList.get(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View)object);
        }
    }
}

添加無限向左循環

可以無限次的向左滑動,需要對PagerAdapter的2個方法進行修改

return Integer.MAX_VALUE:viewpager裡面有幾乎無窮多個object
imageList.get(position % imageList.size());防止角標越界
//表示viewpager共存放了多少個頁面
@Override
public int getCount() {
    return Integer.MAX_VALUE;//我們設置viewpager中有Integer.MAX_VALUE個頁面
}
/**
 * position % imageList.size() 而不是position,是為了防止角標越界異常
 * 因為我們設置了viewpager子頁面的數量有Integer.MAX_VALUE,而imageList的數量只是5。
 */
@Override
public Object instantiateItem(ViewGroup container, int position) {
    container.addView(imageList.get(position % imageList.size()));
    return imageList.get(position % imageList.size());
}
但是這樣暴露一個缺點,就是可以向左滑動,但是當前頁是第一頁的時候,無法向右滑動,因為第一頁的position是0。

解決方法:
    給viewpager設置當前頁是第1000頁,這樣當前頁的左邊還有999頁,右邊還有Integer.MAX_VALUE - 1000頁,
    無論是999,還是(Integer.MAX_VALUE - 1000),一般情況下是滑不到第一頁或最後一頁的。
    當然1000是自己設置的,也可以設置多加幾個0。

添加無限向右循環

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context = this;
    initData();
    viewpager = (ViewPager) findViewById(R.id.viewpager);
    viewpager.setAdapter(new MyAdapter());
    viewpager.setCurrentItem(1000);//當前頁是第1000頁 
}

添加自動循環

上面只是實現了無限循環,但還是用手動的,我們需要它每個一段時間(2秒)滑動一次。這就需要用到handler

int msgWhat = 0;
private Handler handler = new Handler(){
    public void handleMessage(android.os.Message msg) {
        viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);//收到消息,指向下一個頁面
        handler.sendEmptyMessageDelayed(msgWhat, 2000);//2S後在發送一條消息,由於在handleMessage()方法中,造成死循環。
        Log.d(tag, "handleMessage");
    };
};
同時在onCreat()方法中發送消息:handler.sendEmptyMessageDelayed(msgWhat, 2000);

出現的bug

Bug1:內存洩露

Bug:雖然我們實現了 無限自動循環功能,但當我們由MainActivity調轉到SecondActivity的時候,通過Log.d(tag, “handleMessage”);發現handler還在發送消息,這就是內存洩露,所以我們需要在ManiActivity不可見不可交互的時候移除message。

解決方法:在onStop()裡移除message
/**
 * 當MainActivity不可見的時候讓handler停止發送消息
 * 防止內存洩露
 */
@Override
protected void onStop() {
    super.onStop();
    handler.removeMessages(msgWhat);
}

Bug2:再次回到 當前頁,viewpager不再自動循環

由於我們把handler.sendEmptyMessageDelayed(msgWhat, 2000);寫在了onCreate(),當我們由MainActivity調轉到SecondActivity的時候,在回來MainActivity的時候,MainActivity並沒有被銷毀,onCreate()方法並不會再執行。

解決方法:寫在onResume()裡面
/**
 * activity可見可交互的時候就開始發送消息,開啟循環
 */
@Override
protected void onResume() {
    super.onResume();
    handler.sendEmptyMessageDelayed(msgWhat, 2000);
}

所以,最後的完整代碼是:

public class MainActivity extends Activity {

    protected static final String tag = "MainActivity";
    private ViewPager viewpager;
    private List imageList = new ArrayList();
    private Context context;
    int msgWhat = 0;
    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);//收到消息,指向下一個頁面
            handler.sendEmptyMessageDelayed(msgWhat, 2000);//2S後在發送一條消息,由於在handleMessage()方法中,造成死循環。
            Log.d(tag, "handleMessage");
        };
    };
    private Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;
        initData();
        viewpager = (ViewPager) findViewById(R.id.viewpager);
        viewpager.setAdapter(new MyAdapter());
        viewpager.setCurrentItem(1000);//當前頁是第1000頁

        // Button只是為了驗證內存洩露
        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(context, SecondActivity.class);
                startActivity(intent);
            }
        });
    }

    private void initData() {
        imageList.clear();
        ImageView iva = new ImageView(context);
        iva.setBackgroundResource(R.drawable.a);

        ImageView ivb = new ImageView(context);
        ivb.setBackgroundResource(R.drawable.b);

        ImageView ivc = new ImageView(context);
        ivc.setBackgroundResource(R.drawable.c);

        ImageView ivd = new ImageView(context);
        ivd.setBackgroundResource(R.drawable.d);

        ImageView ive = new ImageView(context);
        ive.setBackgroundResource(R.drawable.e);

        imageList.add(iva);
        imageList.add(ivb);
        imageList.add(ivc);
        imageList.add(ivd);
        imageList.add(ive);
    }

    public class MyAdapter extends PagerAdapter{
        //表示viewpager共存放了多少個頁面
        @Override
        public int getCount() {
            return Integer.MAX_VALUE;//我們設置viewpager中有Integer.MAX_VALUE個頁面
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        /**
         * position % imageList.size() 而不是position,是為了防止角標越界異常
         * 因為我們設置了viewpager子頁面的數量有Integer.MAX_VALUE,而imageList的數量只是5。
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(imageList.get(position % imageList.size()));
            return imageList.get(position % imageList.size());
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View)object);
        }
    }

    /**
     * activity可見可交互的時候就開始發送消息,開啟循環
     */
    @Override
    protected void onResume() {
        super.onResume();
        handler.sendEmptyMessageDelayed(msgWhat, 2000);
    }

    /**
     * 當MainActivity不可見的時候讓handler停止發送消息
     * 防止內存洩露
     */
    @Override
    protected void onStop() {
        super.onStop();
        handler.removeMessages(msgWhat);
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved