自动无限轮播

一觉起来,满怀期待,外面应该是大雪纷飞,银装素裹吧。可是依然是浓重的雾霾天,说好的下雪呢?! 北京的天气估计已经被很多人吐槽了吧!一到冬天,pm2.5爆表。。。。撤的有点远了。
今天主要总结一下使用viewpager做自动无限轮播图。前段时间项目中要使用viewpager做轮播,要求是一张图的时候没有轮播效果,两张及两张以上的时候开始自动无限轮播,在手指按下的时候不轮播,手指抬起的时候继续轮播,并且点击图片需要跳转到新界面。这个要求还是蛮简单的,github上也有类似的库:banner,写的很不错的,就是缺少手指按下和抬起的处理。所以自己动手写了一个自动无限轮播。
一说到无限轮播,我们自然会想到使用ViewPager来实现,只要让ViewPager的适配器PagerAdapter中的getCount()函数返回值为无穷大,然后在instantiateItem()函数中显示我们对应的图片,无限轮播功能就算完成了。自动轮播功能我们一般都是使用Handler来发送一个延时消息,然后在处理这个消息的时候再发送一个延时消息,知道 Handler消息处理机制 就懂这个原理。点击图片跳转到新界面这个更简单,只要给ImageVeiw设置一个点击监听就ok了。手指按下停止轮播,手指抬起开始轮播,这个功能只要监听ViewPager的OnTouchEvent触摸事件,然后在手指按下的时候移除掉消息,手指抬起的时候继续发送延时消息就好了。分析完成以后,就开始高兴撸起代码来。但是并不是想象的那么简单,这里我们少分析了一点:ImageView是在ViewPager容器中的,那么给ImageView设置点击事件和ViewPager设置触摸监听事件的时候,出现了事件冲突问题,不是太了解 android事件传递机制 的可以自行百度。这里我们很巧妙的做了一个点击监听,来替换掉系统的点击监听事件。这里面主要涉及两个类: BannerVierPager 和 ViewPagerAdapter ,具体的就看下面代码吧。在写的过程中想练练使用代码布局,感觉还是挺爽了 哈哈。。。

  1. BannerViewPager:该类继承FrameLayout,内部封装了ViewPager,在手指按下停止轮播,手指抬起开始轮播,点击跳转对应新界面的功能都封装在ViewPager的onTouchEvent触摸事件中。我们在手指按下的时候获取按下是x,y以及按下时候的毫秒值,然后在手指抬起的时候获取此时x,y以及手指抬起的当前时间,然后判断如果x ,y 的偏移量都小于10,并且手指抬起的时间与按下的时间差小于500那么就算是一次点击事件,在该点击事件中处理我们的逻辑,比如跳转新界面。具体的可以看OnPagerTouchListener 类中的处理。
public class BannerViewPager extends FrameLayout {

    private static final String tag = "BannerViewPager";

    private Context context;
    private ViewPager viewPager;
    private ViewPagerAdapter adapter;
    private Handler handler;
    private RunnableTask runnableTask;
    private boolean isScroll;
    private OnPagerItemClickListner mOnPageItemClickListener;
    private TextView tvOverViewText;

    public BannerViewPager(Context context) {
        this(context,null);
    }

    public BannerViewPager(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public BannerViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        initView();
        initData();
        setListener();
    }

    private void initView(){
        //添加viewpaer
        viewPager = new ViewPager(context);
        FrameLayout.LayoutParams viewPagerParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT , LayoutParams.MATCH_PARENT);
        viewPager.setLayoutParams(viewPagerParams);
        this.addView(viewPager);
        //添加透明遮罩
        LinearLayout linearLayout = new LinearLayout(context);
        FrameLayout.LayoutParams linearParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT , 60);
        linearParams.gravity = Gravity.BOTTOM;
        linearLayout.setLayoutParams(linearParams);
        linearLayout.setBackgroundColor(Color.parseColor("#78555555"));
        //透明遮罩上添加标题
        tvOverViewText = new TextView(context);
        tvOverViewText.setMaxLines(1);
        tvOverViewText.setLines(1);
        tvOverViewText.setTextColor(Color.WHITE);
        tvOverViewText.setTextSize(16);
        tvOverViewText.setGravity(Gravity.CENTER_VERTICAL);
        tvOverViewText.setEllipsize(TextUtils.TruncateAt.END);
        LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(0 , LinearLayout.LayoutParams.MATCH_PARENT);
        titleParams.weight = 1;
        titleParams.setMargins(15,0,15,0);
        tvOverViewText.setLayoutParams(titleParams);
        linearLayout.addView(tvOverViewText);
        this.addView(linearLayout);
    }

    private void initData(){
        viewPager.setAdapter(adapter = new ViewPagerAdapter(context));
        handler = new Handler();
    }

    /**
     * 添加监听
     */
    private void setListener(){
        viewPager.setOnTouchListener(new OnPagerTouchListener());
        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                if(tvOverViewText != null)
                tvOverViewText.setText(adapter.get(position).picUrl);
            }

            @Override
            public void onPageSelected(int position) { }
            @Override
            public void onPageScrollStateChanged(int state) {}
        });
    }

    /**
     * 添加ViewPager的触摸事件,当手指按下的时候不轮播,抬起的时候轮播,处理点击事件
     */
    private class OnPagerTouchListener implements View.OnTouchListener{

        private long downSystemMills;
        private float downX;
        private float downY;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    downX = event.getX();
                    downY = event.getY();
                    stopScroll();
                    downSystemMills = System.currentTimeMillis();
                    break;
                case MotionEvent.ACTION_MOVE:
                    break;
                case MotionEvent.ACTION_UP:
                    float upX = event.getX();
                    float upY = event.getY();
                    long upSystemMills = System.currentTimeMillis();
                    float offDownX = upX - downX;
                    float offDownY = upY - downY;
                    if (Math.abs(offDownX) < 10 && Math.abs(offDownY) < 10) {
                        if (upSystemMills - downSystemMills < 500 && mOnPageItemClickListener != null) {
                            mOnPageItemClickListener.onPagerItemClickListner(viewPager.getCurrentItem()%adapter.getRealCount() , adapter.get(viewPager.getCurrentItem()));
                        }
                    }
                    startScroll();
                    break;
            }
            return false;
        }
    }

    public void setOnPageItemClickListener(OnPagerItemClickListner clickListener){
        this.mOnPageItemClickListener = clickListener;
    }

    /**
     * 设置数据
     * @param beans
     */
    public void setData(List<BannerBean> beans){
        this.adapter.addAll(beans);
        this.viewPager.setCurrentItem(beans.size()*1000);
    }

    /**
     * 开始轮播
     */
    public void startScroll(){
        if(!isScroll){
            getRunnableTask().startScroll();
            isScroll = true;
        }
    }

    /**
     * 停止轮播
     */
    public void stopScroll(){
        if(isScroll){
            getRunnableTask().stopScroll();
            isScroll = false;
        }
    }

    /**
     * 获取轮播任务
     * @return
     */
    private RunnableTask getRunnableTask(){
        if(runnableTask == null){
            synchronized(this){
                if(runnableTask == null)
                    runnableTask = new RunnableTask();
            }
        }
        return runnableTask;
    }

    /**
     * 自动轮播任务
     */
    private class RunnableTask implements Runnable{

        public void startScroll(){
            handler.postDelayed(this , 5000);
        }

        @Override
        public void run() {
            int position = viewPager.getCurrentItem() + 1;
            viewPager.setCurrentItem(position , true);
            startScroll();
        }

        public void stopScroll(){
            handler.removeCallbacks(this);
        }

    }

    /**
     * 每个条目的点击事件
     * @param <T>
     */
    public interface OnPagerItemClickListner<T>{
        void onPagerItemClickListner(int position ,T t);
    }

}
  1. ViewPagerAdapter :在这个类中我们还需要处理一点小问题:轮播图为一个的时候不轮播,轮播图超过一个的时候需要轮播,但是ViewPager轮播的时候最少需要4页,因为ViewPager在预初始化时候会初始化当前页面以及左右一页,如果轮播的时候数据刚好是两页或者三页,那么就会报已经有一个Parent错误,我们可以在每次添加的时候先获取到当前ImageView的Parent,从Parent中移除掉ImageView,然后在添加,这样还是行不通,在轮播的时候会出现空白页,还是预初始话的问题,这里也没有其他好的解决办法。就在判断当数据是两条或者三条的时候,让它在添加2条或3条数据来占坑。具体方式看setUpData()中的处理。
public class ViewPagerAdapter extends PagerAdapter {

    private List<BannerBean> beanList ;
    private List<ImageView> imageViews;
    private Context context;
    private int realCount;

    public ViewPagerAdapter(Context context){
        this.imageViews = new ArrayList<>();
        this.beanList = new ArrayList<>();
        this.context = context;
    }

    /**
     * 添加轮播数据
     * @param beanList
     */
    public void addAll(List<BannerBean> beanList){
        reset();
        this.beanList.addAll(beanList);
        this.realCount = this.beanList.size();
        setUpData();
        addImages();
        this.notifyDataSetChanged();
    }

    /**
     * 重置
     */
    private void reset(){
        this.beanList.clear();
        this.realCount = 0;
        this.imageViews.clear();
    }

    /**
     * 获取对应位置上的轮播图数据对象
     * @param position
     * @return
     */
    public BannerBean get(int position){
        return this.beanList.get(position % this.beanList.size());
    }

    /**
     * 获取真实大小
     * @return
     */
    public int getRealCount(){
        return realCount;
    }

    @Override
    public int getCount() {
        return this.beanList.size() > 1 ? Integer.MAX_VALUE : this.beanList.size();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        position = position % this.beanList.size();
        ImageView iv = imageViews.get(position);
        BannerBean bean = this.beanList.get(position);
        ImageLoader.displayImage(context , iv , bean.picUrl);
        container.addView(iv);
        return iv;
    }

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

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

    /**
     * 修正数据
     */
    private void setUpData(){
        if(realCount == 2 || realCount == 3){
            for(int i=0; i<realCount ;i++){
                BannerBean bean = this.beanList.get(i);
                this.beanList.add(bean);
            }
        }
    }

    /**
     * 添加录播图片
     */
    private void addImages(){
        int count = this.beanList.size();
        for(int i=0;i<count;i++){
            ImageView iv = new ImageView(context);
            iv.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageViews.add(iv);
        }
    }

}

3.使用起来也非常简单

        bannerViewPager.setData(beans);  //设置数据
        bannerViewPager.startScroll();   // 开始轮播
        //添加点击监听
        bannerViewPager.setOnPageItemClickListener(new   BannerViewPager.OnPagerItemClickListner<BannerBean>() {
            @Override
            public void onPagerItemClickListner(int position, BannerBean bean) {
                Log.e(tag , position + "  .....  " + bean.picUrl);
                Toast.makeText(MainActivity.this, "position: "+position,Toast.LENGTH_SHORT).show();
            }
        });
    }
    //停止轮播,该方法需要在Activity或者Fragment的onDestroy中调用一次,防止出现内存泄漏问题。
    bannerViewPager.stopScroll();

源码下载

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值