天天看點

自定義輪播圖,實作無限輪播、自動輪播、按下停止輪播

本文将所有輪播圖的功能實作全放在了自定義ViewPager中,若你的ViewPager需要實作輪播功能,隻需要将ViewPager替換為CycleViewPager(注:本文V4包為低版本,如有需要,請自行将監聽更改為addOnPageChangeListener)。

首頁面代碼與正常使用ViewPager一緻,示範采用的是在代碼中執行個體CycleViewPager對象:

MainActivity代碼如下:

package zz.qby.cycleviewpager;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.ImageView;

/**
 * 顯示首頁面
 * @author qby
 */
public class MainActivity extends Activity {

    private FrameLayout fl_cycleview;
    private int[] resIds = new int[] { R.drawable.image1, R.drawable.image2,
            R.drawable.image3, R.drawable.image4, R.drawable.image5 };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fl_cycleview = (FrameLayout) findViewById(R.id.fl_cycleview);

        MyPageAdapter adapter = new MyPageAdapter();
        viewPager.setAdapter(adapter);

        // 可使用工具類将dp轉為px設定給LayoutParams
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                LayoutParams.MATCH_PARENT, );
        fl_cycleview.addView(viewPager, params);
    }

    private class MyPageAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return resIds.length;
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView iv = new ImageView(getApplicationContext());
            iv.setBackgroundResource(resIds[position]);
            container.addView(iv);
            return iv;
        }

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

    }

}
           

布局代碼很簡單:

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <FrameLayout
        android:id="@+id/fl_cycleview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
         >
    </FrameLayout>

</LinearLayout>
           

下面是本文重點,自定義ViewPager的代碼:

package zz.qby.cycleviewpager;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author qby
 * @project CycleViewPager
 * @create_time 00:08:36
 * @des 自定義輪播圖,實作無限輪播、自動輪播、觸摸停止自動輪播
 */
public class CycleViewPager extends ViewPager {

    //handler實作自動輪播
    private static final int scrollTask = ;
    private InnerAdapter innerAdapter;
    private int position;

    public CycleViewPager(Context context) {
        super(context);
    }

    public CycleViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 重寫頁面改變監聽
     */
    @Override
    public void setOnPageChangeListener(OnPageChangeListener listener) {
        InnserOnPageChangeListener innserOnPageChangeListener = new InnserOnPageChangeListener(
                listener);
        super.setOnPageChangeListener(innserOnPageChangeListener);

    }

    /**
     * 自定義監聽器實作頁面改變的監聽
     * @author qby
     *
     */
    public class InnserOnPageChangeListener implements OnPageChangeListener {

        private OnPageChangeListener listener;

        public InnserOnPageChangeListener(OnPageChangeListener listener) {
            this.listener = listener;
        }

        @Override
        public void onPageScrolled(int position, float positionOffset,
                int positionOffsetPixels) {
            if (listener != null)
                listener.onPageScrolled(position, positionOffset,
                        positionOffsetPixels);
        }

        @Override
        public void onPageSelected(int position) {
            CycleViewPager.this.position = position;
            if (listener != null)
                listener.onPageSelected(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            // 空閑 IDLE
            if (state == ViewPager.SCROLL_STATE_IDLE) {
                if (position == innerAdapter.getCount() - ) {
                    // A 最後一個條目
                    // 切換到position = 1的 條目
                    // 悄悄的切換
                    CycleViewPager.this.setCurrentItem(, false);
                } else if (position == ) {
                    // D
                    CycleViewPager.this.setCurrentItem(
                            innerAdapter.getCount() - , false);
                }
            }
            if (listener != null)
                listener.onPageScrollStateChanged(state);

        }
    }

    // 修正adapter
    @Override
    public void setAdapter(PagerAdapter adapter) {
        // 修正adapter
        // innerAdapter [DABCDA]
        innerAdapter = new InnerAdapter(adapter);
        //設定頁面改變的監聽,因為不需要用參數的listener做其他操作,傳入null即可
        //高版本V4包,可使用addOnPageChangeLstener
        setOnPageChangeListener(null);
        super.setAdapter(innerAdapter);
        // 切換到 A
        this.setCurrentItem();

        // 啟動輪播
        startScroll();
    }
        //設定輪播間隔為2秒
    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case scrollTask:
                handler.removeMessages(scrollTask);
                CycleViewPager.this.setCurrentItem(position++);
                handler.sendEmptyMessageDelayed(scrollTask, );
                break;

            default:
                break;
            }
        }
    };

    /**
     * 啟動輪播
     */
    private void startScroll() {
        handler.sendEmptyMessageDelayed(scrollTask, );

    }

    /**
     * 修正傳入adapter的索引
     * @author qby
     *
     */
    public class InnerAdapter extends PagerAdapter {

        private PagerAdapter adapter;

        public InnerAdapter(PagerAdapter adapter) {
            this.adapter = adapter;
        }

        @Override
        public int getCount() {
            return adapter.getCount() + ;
        }

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

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            // position [0,1,2,3,4,5]
            // 修正 position
            if (position == ) {
                // D --- >找到原來集合中的索引
                position = adapter.getCount() - ;
            } else if (position == getCount() - ) {
                // A
                position = ;
            } else {
                position -= ;
            }

            return adapter.instantiateItem(container, position);
        }
    }

    /**處理按下時不自動輪播,松開後自動輪播*/
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // 手指按下移除消息
            handler.removeMessages(scrollTask);
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        // 細節,觸摸可能在控件外才擡起,此時隻能監聽到取消事件
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            startScroll();
            break;
        }

        return super.onTouchEvent(ev);
    }
}