天天看点

自定义轮播图,实现无限轮播、自动轮播、按下停止轮播

本文将所有轮播图的功能实现全放在了自定义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);
    }
}