ViewPager系列之ViewPager无限循环滑动

目前ViewPager实现无限循环有2种方法,直接上具体方法:


方法1:重写 PagerAdapter 中的 getCount() 方法。其实只是在计算item 数目的时候给了一个很大的数,然后通过调用setCurrentItem(position)方法,相当于把起始位置放到了中间的某个位置而已。这里在重写instantiateItem()方法的时候,记得角标的大小,这里就就不上具体代码了。

@Override
public int getCount() {
    return Integer.MAX_VALUE;
}
  • 1
  • 2
  • 3
  • 4
  • 5

方法2:重写了 OnPageChangeListener 接口中的onPageSelected 方法。先上一下效果图,大家一定要留意git图的页面切换效果。

ViewPager无限循环

gif图效果看的不明显,其实这里是有瑕疵的。在循环的第一张和最后一张会有点不太协调(我这里是蓝色海洋和 路飞艾斯这两张图片的切换),之前录了个清晰的git可以清楚的看到这一点,但是因为图片上传不能超过2M,修改gif后看得不明显了,具体的还是自己尝试下才清楚。


ViewPager无限循环原理分析:

ViewPager真实无限循环

如果旧数据是的结构是 List 1,2,3。 那么拼接的新数据格式为List 3,1,2,3,1。

初始化我们让ViewPager指向position=1这个位置,也就是List<旧数据的第一条数据>。如果向左滑动,那么当前显示的List<0>这个页面,也就是List<新数据的第一条数据>,这会儿我们让ViewPager重新指向红色3的位置,也就是List<新数据长度-2>。这样ViewPager就可以向左向右进行滑动了。

如果当前位置是在红色3的页面,也就是List<旧数据最后一条>数据对应的页面。如果向右滑动,那么当前显示的List<新数据长度-1>这个也页面,当滑动到这个页面时会重新setCurrentItem 指定到第一条数据。


ViewPager无限循环Demo代码

xml 布局

    <android.support.v4.view.ViewPager
         android:id="@+id/viewPager"
         android:layout_width="match_parent"
         android:layout_height="match_parent">        
    </android.support.v4.view.ViewPager>
  • 1
  • 2
  • 3
  • 4
  • 5

Activity 代码

        // 留意这里的顺序。
        list2.add(R.drawable.image_08);
        list2.add(R.drawable.image_06);
        list2.add(R.drawable.image_07);
        list2.add(R.drawable.image_08);
        list2.add(R.drawable.image_06);

        mVviewPager = (ViewPager) findViewById(R.id.viewPager);
        // 这里的MultiplePagerAdapter2不用管,我直接用的其他的adapter.具体的看需求了。
        MultiplePagerAdapter2 adapter2 = new MultiplePagerAdapter2(this, list2);
        mVviewPager.setAdapter(adapter2);
        // 初始化指定位置
        mVviewPager.setCurrentItem(1);
        // 重点看下面的代码
        mVviewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            int currentPosition;

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                currentPosition = position;
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                // ViewPager.SCROLL_STATE_IDLE 标识的状态是当前页面完全展现,并且没有动画正在进行中,如果不
                // 是此状态下执行 setCurrentItem 方法回在首位替换的时候会出现跳动!
                if (state != ViewPager.SCROLL_STATE_IDLE) return;

                // 当视图在第一个时,将页面号设置为图片的最后一张。
                if (currentPosition == 0) {
                    mVviewPager.setCurrentItem(list2.size() - 2, false);

                } else if (currentPosition == list2.size() - 1) {
                    // 当视图在最后一个是,将页面号设置为图片的第一张。
                    mVviewPager.setCurrentItem(1, false);
                }
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

ViewPager无限循环两种方法比较:

流畅性:第一种方法 显然要比第二种方法要流畅很多。

应用场景: 如果只是让用户自行滑动跳转pager 的话,我比较推荐第一种。毕竟流畅性要好很多。如果是定时无限循环的话,可以尝试用第二种方法。当然具体在pager转场动画里是直接跳转还是有个过渡动画来缓冲一下,看具体的项目中更适合哪种了。


介绍下 setCurrentItem (int item, boolean smoothScroll) 和 setCurrentItem (int item) 的区别。

其实谷歌文档已经介绍的很详细了。

public void setCurrentItem (int item, boolean smoothScroll)
Set the currently selected page. // 设定当前选择的页面
参数
item int: Item index to select
smoothScroll boolean: True to smoothly scroll to the new item, false to transition immediately
// 如果smoothScroll 为true,则平滑滚动到指定页面,false 则直接跳转到指定页面

public void setCurrentItem (int item)
Set the currently selected page. If the ViewPager has already been through its first layout with its current adapter there will be a smooth animated transition between the current item and the specified item.
// 设定当前选择的页面。如果ViewPager 已经通过指定页面,那么将会在当前iten 与指定item 有一个平滑的过渡动画。
参数
item int: Item index to select

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现 ViewPager 的循环滑动,可以通过以下步骤: 1. 继承 ViewPager 类,重写 `onTouchEvent` 方法,使其支持循环滑动。 ```java public class LoopViewPager extends ViewPager { public LoopViewPager(Context context) { super(context); } public LoopViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { stopAutoScroll(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { startAutoScroll(); } return super.onTouchEvent(event); } } ``` 2. 重写 `onMeasure` 方法,使其支持 wrap_content。 ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); if (h > height) { height = h; } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } ``` 3. 重写 `setAdapter` 方法,使其支持循环滑动。 ```java @Override public void setAdapter(PagerAdapter adapter) { super.setAdapter(adapter); setCurrentItem(0); } @Override public void setCurrentItem(int item) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item); return; } int position = getRealPosition(item); super.setCurrentItem(position); } private int getRealCount() { PagerAdapter adapter = getAdapter(); if (adapter == null) { return 0; } return adapter.getCount(); } private int getRealPosition(int position) { int realCount = getRealCount(); if (realCount == 0) { return 0; } return position % realCount; } ``` 4. 在 `onPageSelected` 回调中处理循环滑动的逻辑。 ```java @Override public void onPageSelected(int position) { int realCount = getRealCount(); if (realCount == 0) { return; } int realPosition = getRealPosition(position); if (realPosition == 0) { setCurrentItem(realCount, false); } else if (realPosition == realCount - 1) { setCurrentItem(1, false); } } ``` 5. 在 `startAutoScroll` 和 `stopAutoScroll` 方法中处理自动滑动的逻辑。 ```java private void startAutoScroll() { stopAutoScroll(); mHandler.postDelayed(mAutoScrollTask, mInterval); } private void stopAutoScroll() { mHandler.removeCallbacks(mAutoScrollTask); } private Runnable mAutoScrollTask = new Runnable() { @Override public void run() { int currentItem = getCurrentItem(); setCurrentItem(currentItem + 1, true); mHandler.postDelayed(this, mInterval); } }; ``` 完整的实现代码如下: ```java public class LoopViewPager extends ViewPager { private static final int DEFAULT_INTERVAL = 3000; private Handler mHandler = new Handler(); private int mInterval = DEFAULT_INTERVAL; public LoopViewPager(Context context) { super(context); init(); } public LoopViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setPageTransformer(true, new DefaultTransformer()); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { stopAutoScroll(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { startAutoScroll(); } return super.onTouchEvent(event); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); if (h > height) { height = h; } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override public void setAdapter(PagerAdapter adapter) { super.setAdapter(adapter); setCurrentItem(0); } @Override public void setCurrentItem(int item) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item); return; } int position = getRealPosition(item); super.setCurrentItem(position); } @Override public void setCurrentItem(int item, boolean smoothScroll) { int realCount = getRealCount(); if (realCount == 0) { super.setCurrentItem(item, smoothScroll); return; } int position = getRealPosition(item); super.setCurrentItem(position, smoothScroll); } @Override public int getCurrentItem() { int realCount = getRealCount(); if (realCount == 0) { return super.getCurrentItem(); } int position = super.getCurrentItem(); return getRealPosition(position); } private int getRealCount() { PagerAdapter adapter = getAdapter(); if (adapter == null) { return 0; } return adapter.getCount(); } private int getRealPosition(int position) { int realCount = getRealCount(); if (realCount == 0) { return 0; } return position % realCount; } @Override public void onPageSelected(int position) { int realCount = getRealCount(); if (realCount == 0) { return; } int realPosition = getRealPosition(position); if (realPosition == 0) { setCurrentItem(realCount, false); } else if (realPosition == realCount - 1) { setCurrentItem(1, false); } } public void setInterval(int interval) { mInterval = interval; } public void startAutoScroll() { stopAutoScroll(); mHandler.postDelayed(mAutoScrollTask, mInterval); } public void stopAutoScroll() { mHandler.removeCallbacks(mAutoScrollTask); } private Runnable mAutoScrollTask = new Runnable() { @Override public void run() { int currentItem = getCurrentItem(); setCurrentItem(currentItem + 1, true); mHandler.postDelayed(this, mInterval); } }; private static class DefaultTransformer implements ViewPager.PageTransformer { @Override public void transformPage(View page, float position) { if (position < -1) { page.setAlpha(0); } else if (position <= 1) { float scaleFactor = Math.max(0.75f, 1 - Math.abs(position - 0.125f)); page.setScaleX(scaleFactor); page.setScaleY(scaleFactor); } else { page.setAlpha(0); } } } } ``` 使用方式: ```xml <com.example.LoopViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="wrap_content" /> ``` ```java LoopViewPager viewPager = findViewById(R.id.view_pager); PagerAdapter adapter = new MyPagerAdapter(); viewPager.setAdapter(adapter); viewPager.setInterval(3000); viewPager.startAutoScroll(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值