Android輪播循環Banner修正進度條同步圖片切換

上次更新的一個Banner的輪播循環,經過測試,發現存在一定的問題,就是當用戶手動切換banner圖片的時候,banner的計時沒有重新開始。

具體說一下問題所在,設置3s更換一張banner,如果我在2s的時候手動滑動banner,到下一張banner的圖片,那麼只需要1s就對當前的圖片進行切換了,對於追求完美的程序員來說,是不可以忍受的,所以我查閱了多方資料,進行了修正更改。

具體分析原因的話就是因爲Thread線程,當你手動的時候,這個線程並沒有暫停結束,還在繼續運行着,所以當用戶手動滑動的話,線程還在繼續,3s的時間跑完繼續currentItem+1,導致問題的所在,我們現在要解決的問題就是當用戶滑動的時候,要將線程暫停,然後重新計時3s,重新開始運行這個線程。

原因分析完了,最新的這部分代碼,加了一個進度條來進行監控,可以讓我們的進度條跟隨着圖片一起進行切換,圖片切換,進度條走滿,手動切換圖片,進度條重新開始走,並且圖片計時重新開始3s的計時。

廢話了這麼多了,上ImageHandler的代碼吧:

import android.os.Handler;
import android.os.Message;
import java.lang.ref.WeakReference;

/**
 * Created by Administrator on 2016/8/12 0012.
 */
public class ImageHandler extends Handler {

    /**
     * 請求更新顯示的View
     */
    protected static final int MSG_UPDATE_IMAGE = 1;
    /**
     * 請求暫停輪播
     */
    protected static final int MSG_KEEP_SILENT = 2;
    /**
     * 請求恢復輪播
     */
    protected static final int MSG_BREAK_SILENT = 3;
    /**
     * 記錄最新的頁號,當用戶手動滑動時需要記錄新頁號,否則會使輪播的頁面出錯。
     * 例如當前如果在第一頁,本來準備播放的是第二頁,而這時候用戶滑動到了末頁,
     * 則應該播放的是第一頁,如果繼續按照原來的第二頁播放,則邏輯上有問題。
     */
    protected static final int MSG_PAGE_CHANGED = 4;

    //輪播間隔時間
    protected static final long MSG_DELAY = 6000;

    //使用弱引用避免Handler泄露.這裏的泛型參數可以不是Activity,也可以是Fragment    private WeakReference<IndexActivity> weakReference;
    private int currentItem = 0;

    protected ImageHandler(WeakReference<IndexActivity> wk) {
        weakReference = wk;
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        final IndexActivity activity = weakReference.get();
        if (activity == null) {
            //Activity已經回收,無需再處理UI            return;
        }
        //檢查消息隊列並移除未發送的消息,這主要是避免在複雜環境下消息出現重複等問題。
        if (activity.handler.hasMessages(MSG_UPDATE_IMAGE)) {
            activity.handler.removeMessages(MSG_UPDATE_IMAGE);
        }
        switch (msg.what) {
            case MSG_UPDATE_IMAGE:
                currentItem++;
                activity.viewPager.setCurrentItem(currentItem);
                new Thread(new Runnable() {

                    @Override
                    public void run() {

                        for (int i = 0; i <= 100; i++) {
                            if (Onn.isOff) {
                                activity.progressBar.setProgress(0);
                                i=0;
                                Onn.isOff = false;
                                continue;
                            }
                            activity.progressBar.setProgress(i);
                            try {
                                Thread.sleep(60);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }).start();
                //準備下次播放
                activity.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);

                break;
            case MSG_KEEP_SILENT:
                //只要不發送消息就暫停了
                break;
            case MSG_BREAK_SILENT:
                activity.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY);
                break;
            case MSG_PAGE_CHANGED:
                //記錄當前的頁號,避免播放的時候頁面顯示不正確。
                currentItem = msg.arg1;
                break;
            default:
                break;
        }
    }
}
個人重點記錄一下線程中的東西,其他地方的代碼很好理解。以後可以參考使用。

線程中的Onn.isOff,是我們自己定義的一個全局變量。


/**
 * Created by Administrator on 2016/8/12 0012.
 */
public class Onn {

    public static boolean isOff = false;

}
這個全局變量是判斷我們的線程狀態。默認狀態是false。for循環中,走的就是我們的進度條的一個動態效果。但是手動切換圖片的話,我們的進度條要歸零,並且從0開始重新走。這是我們的需求。實現的邏輯就是,當我們手動切換圖片的時候,isOff設爲true,然後將進度條歸零,再將isOff設爲false,continue,就繼續開始走我們的進度條了。如果正常狀態,沒有切換,那我們就不走if,直接走我們的進度條啦。

具體的activity中的操作代碼如下:

ImageHandler handler = new ImageHandler(new WeakReference<IndexActivity>(this));

LayoutInflater inflater = LayoutInflater.from(this);
ImageView view1 = (ImageView) inflater.inflate(R.layout.item_viewpager, null);
ImageView view2 = (ImageView) inflater.inflate(R.layout.item_viewpager, null);
ImageView view3 = (ImageView) inflater.inflate(R.layout.item_viewpager, null);
view1.setImageResource(R.mipmap.banner_test);
view2.setImageResource(R.mipmap.banner_test);
view3.setImageResource(R.mipmap.banner_test);
ArrayList<ImageView> views = new ArrayList<ImageView>();
views.add(view1);
views.add(view2);
views.add(view3);
viewPager.setAdapter(new ImageAdapter(views));
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

    //配合AdaptercurrentItem字段進行設置。
    @Override
    public void onPageSelected(int arg0) {
        handler.sendMessage(Message.obtain(handler, ImageHandler.MSG_PAGE_CHANGED, arg0, 0));
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    }

    //覆寫該方法實現輪播效果的暫停和恢復
    @Override
    public void onPageScrollStateChanged(int arg0) {
        switch (arg0) {
            case ViewPager.SCROLL_STATE_DRAGGING:
                handler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT);
                Onn.isOff = true;
                break;
            case ViewPager.SCROLL_STATE_IDLE:
                handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);
                break;
            default:
                break;
        }
    }
});
viewPager.setCurrentItem(0);//默認在中間,使用戶看不到邊界
new Thread(new Runnable() {

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            progressBar.setProgress(i);
            try {
                Thread.sleep(60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}).start();
//開始輪播效果
handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY);

這裏爲什麼又單獨寫了一個Thread線程來走我們的進度條呢,如果按照上述的操作完,你會發現,進來以後的第一張圖片是沒有進度條的,所以剛進到這個頁面我們就需要單獨跑一起這個進度條。

還有我們的ImageViewAdapter:

import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;

import java.util.ArrayList;

/**
 * Created by Administrator on 2016/8/10 0010.
 */
public class ImageAdapter extends PagerAdapter {

    private ArrayList<ImageView> viewlist;

    public ImageAdapter(ArrayList<ImageView> viewlist) {
        this.viewlist = viewlist;
    }

    @Override
    public int getCount() {
        //設置成最大,使用戶看不到邊界
        return Integer.MAX_VALUE;
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0==arg1;
    }
    @Override
    public void destroyItem(ViewGroup container, int position,
                            Object object) {
        //Warning:不要在這裏調用removeView
    }
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        //ViewPager頁號求模取出View列表中要顯示的項
        position %= viewlist.size();
        if (position<0){
            position = viewlist.size()+position;
        }
        ImageView view = viewlist.get(position);
        //如果View已經在之前添加到了一個父組件,則必須先remove,否則會拋出IllegalStateException        ViewParent vp =view.getParent();
        if (vp!=null){
            ViewGroup parent = (ViewGroup)vp;
            parent.removeView(view);
        }
        container.addView(view);
        //add listeners here if necessary
        return view;
    }
}

這樣就實現了我們的循環輪播加進度條監控的效果了。大家可以根據自己的需求進行修改,如果不需要進度條的可以自己將Thread的代碼刪除就可以單獨的實現輪播循環的banner。我主要還是爲了記錄一下自己,所以加上了這個進度條的效果狀態。

如果轉載,請標明出處。謝謝。

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