ViewPager实现循环滑动

在Android开发中,ViewPager常用于实现滑动效果,但在默认情况下无法实现循环滑动。本文介绍了三种方法来解决这个问题:一是通过重写adapter的getCount方法;二是添加头尾元素并监听滑动事件进行切换;三是结合OnPageScrollStateChanged方法实现无缝循环。最后提供了完美解决方案的源码链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android中用ViewPager实现循环滑动

ViewPager在android开发中是个非常常用的组件,最为大家所熟悉的应用场景大概是在app中自动滚动的广告了。当然了,还有很多其它的地方也会用它来实现。不过美中不足的是,它没提供相应的API来实现循环滑动,当滑到最后一页后就不能前进了,只能回退,而当退到第一页时也不能再回退了。可我们的需求中往往有些地方需要循环的效果,比如上面说的广告,一般都是在ViewPager中放几张广告图,然后循环地滚动着。这样就要我们想点别的办法来达到要求。

目前网上主要有两种方法来解决这个问题。

方法一:

一种是方式是重写adapter的getCount方法,返回一个很大的数,比如Integer.MAX_VALUE,然后在初始化时从Integer.MAX_VALUE的二分之一处开始显示,因为这个值很大,所以基本不可能滑动到position=0或者position=Integer.MAX_VALUE的位置,使用户感觉是在循环。

其主要代码像这样:

 private class MyAdapter extends PagerAdapter {

    private List<View> listView;

    public MyAdapter(List<View> listView) {
        this.listView = listView;
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int index = position % listView.size();
        int i = container.indexOfChild(listView.get(index));
        if (i != -1) {
            container.removeViewAt(i);
        }
        container.addView(listView.get(index));
        return listView.get(index);
    }

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

实际上这并不是真正的无限循环,如果只应用在手动滑的场景基本上不会出现滑到两端的情况,但如果是自动滑动的话这样做风险就比较大了。

方法二:

第二种方法是在原始数据的基础上增加一个头和尾,例如原始数据为[a1,b1,c1]三条数据,那么我们在头尾各增加一条数据变成[c2,a1,b1,c1,a2],c2与c1,a2与a1的内容是一样的,然后通过OnPageChangeListener中的onPageSelected方法判断viewpager是否滑到了头或滑到了尾,如到了头或尾就重新设置一下ViewPager的当前显示页,比如像上面的数据,当显示c2页的时候,就人为切换到c1,当显示a2的时候就人为切换到a1,这样无论往前往后滑都做到了真正的循环。

其主要代码是这样的:

@Override
public void onPageSelected(int position) {
    if (position == 0) {
        // 如果当前页是第1页,则跳到倒数第二页
        setCurrentItem(mCount - 2, false);
    } else if (position == mCount - 1) {
        // 如果当前页是倒数第一页,则跳到第二页
        setCurrentItem(1, false);
    }
}

不过这种方法有一点瑕疵,就是在头尾切换的时候会闪一下,也就是从a1滑向c2或c1滑向a2的时候,动画还没有完成,即c2或a2还没有显示完整的时候就切到c1或a1去了,给人很不友好的体验,于是就有了本文要介绍的这种方法。

完美解决方案:

本方法的实现原理跟第二种方法是一样的,就是在第二种方法的基础上解决了会闪的问题。会闪的原因是动画还没执行完就已经调用onPageSelected方法了,导致我们的人为切换过早执行了,所以看起来像闪了一下。一开始我在那里加了一个延时,就是等待动画完成再执行切换,但是这个延迟的时间很难掌握,经常出现原本调好的时间到下次执行时又会闪,延时太长了也不行,如果连续滑动的话会滑不过去,要等一下才行,所以这不是个长久之计。后来搜索一番才知道原来有地方可以精确地知道动画已完成,就是onPageScrollStateChanged这个方法里面,当它的参数state的值为SCROLL_STATE_IDLE 时,就代表动画已完成了。这样就好办了,我们可以在这里执行我们的头尾切换工作。

其主要代码像这样:

@Override
public void onPageSelected(int position) {
    System.out.println("onPageSelected--->position = " + position);
    mCurrentItem = position;
}

@Override
public void onPageScrollStateChanged(int state) {
    switch (state) {
        case SCROLL_STATE_IDLE:
            // 已停止滑动
            System.out.println("已停止滑动..." );
            if (mCurrentItem == 0) {
                setCurrentItem(mCount - 2, false);
            } else if (mCurrentItem == mCount - 1) {
                setCurrentItem(1, false);
            }
            break;
        case SCROLL_STATE_DRAGGING:
            // 正在手动拖动
            System.out.println("正在手动拖动..." );
            break;
        case SCROLL_STATE_SETTLING:
            // 正在归位,即松手后自动完成滑动的过程
            System.out.println("正在归位..." );
            break;
    }
}

效果图:

这样就完美的实现了循环滑动了。

最后,上源码:

demo源码:https://github.com/MingHuang1024/CyclicViewPager

番外篇

提个小问题:如果换一个场景,比如在日历中,我们每滑一下就显示下一个月或上一个月的日历,一般做个日历的话都要可以查询上百年的日期吧,如果使用上述方法,难道我们要传N多个view到ViewPagerAdapter里面吗?显然这是不可能的。如果只用三个view呢,让它们循环使用,这也有个问题,你怎么知道它滑到哪年哪月了呢?难道要自己用个计数器把它记起来?会不会太麻烦?下一篇来讲讲如何解决这个问题。请看大屏幕巧用ViewPager实现日历场景



由于水平有限,如果文中存在错误之处,请大家批评指正,欢迎大家一起来分享!

博客:http://blog.youkuaiyun.com/MingHuang2017

GitHub:https://github.com/MingHuang1024

Email:MingHuang1024@foxmail.com

微信:724360018

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值