一. 默认不可以无限循环的状态 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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public class MainActivity extends AppCompatActivity { private int [] resources = {R.drawable.pic_1,R.drawable.pic_2,R.drawable.pic_3}; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager viewPager = findViewById(R.id.pager); viewPager.setOffscreenPageLimit(resources.length); viewPager.setAdapter(new PagerAdapter() { @Override public int getCount () { return resources.length; } @Override public boolean isViewFromObject (@NonNull View view, @NonNull Object object) { return object == view; } @NonNull @Override public Object instantiateItem (@NonNull ViewGroup container, int position) { View inflate = LayoutInflater.from(getApplicationContext()).inflate(R.layout.pager_layout, null ); ImageView imageView = inflate.findViewById(R.id.image_view); imageView.setBackgroundResource(resources[position]); container.addView(inflate); return inflate; } @Override public void destroyItem (@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView((View) object); } }); } } <!-- activity_main.xml ---> <?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:orientation="vertical" > <androidx.viewpager.widget.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="100dp" android:clipChildren="false" /> </LinearLayout> <!-- pager_layout.xml --> <?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/image_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
二. 伪无限循环 如果我们设置 ViewPager 的 页面数量很大,然后在 初始化页面 的函数中对 postion 取余。这就相当于我们创建了很多的一模一样的页面连续的排列在一起,这样向右滑动就会形成无限滑动的效果。虽然,理论上一直向右滑动还是会滑不动,但是一般情况下是不会这么无聊的。
这样还有一个问题,向左滑动还是不能滑动的。但是,如果我们将初始页面设置在中间位置,那么就可以达到无限滑动的效果了。
① 设置步骤:
在 PagerAdapter的getCount 方法中设置 返回值 是一个很大的值。
在 PagerAdapter的instantiateItem 方法中对 position 进行取余操作,一方面是防止数组越界,一方面是为了显示正确的内容。
使用 setCurrentItem 方法,设置 显示的页面 大概处于中间的位置。注意该方法一定要在设置 适配器 之后再调用,否则会没有效果。
② 返回很大的页面会不会影响内存?
我个人觉得,ViewPager默认只会加载两个页面,滑动了之后,还是只加载两个页面,不会对内存造成太大的影响。
参考文章:Android ViewPager 无限轮播Integer.MAX_VALUE 争议(看源码)
③ 在 getCount 方法中 返回 Integer.MAX_VALUE 的问题?
使用Integer.MAX_VALUE会在setCurrentItem()的时候发生ANR,所以还是设置为一个比较大的数比较好。
④ 代码
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class MainActivity extends AppCompatActivity { private int [] resources = {R.drawable.pic_1,R.drawable.pic_2,R.drawable.pic_3}; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager viewPager = findViewById(R.id.pager); viewPager.setAdapter(new PagerAdapter() { @Override public int getCount () { if (resources.length == 1 ){ return 1 ; } return 500 ; } @Override public boolean isViewFromObject (@NonNull View view, @NonNull Object object) { return object == view; } @NonNull @Override public Object instantiateItem (@NonNull ViewGroup container, int position) { int realPosition = position % resources.length; View inflate = LayoutInflater.from(getApplicationContext()).inflate(R.layout.pager_layout, null ); ImageView imageView = inflate.findViewById(R.id.image_view); imageView.setBackgroundResource(resources[realPosition]); container.addView(inflate); return inflate; } @Override public void destroyItem (@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView((View) object); } }); viewPager.setCurrentItem(240 ); } }
⑤ 运行效果
三. 真正的无限循环 假设有三条页面数据,分别是0、1、2。我们再创建一个新的页面数据,长度为真实数据的长度+2,在最前面插入最后一条页面数据2,在最后面插入第一条页面数据0,新的页面数据就变为2、0、1、2、0。设置新的页面数据为ViewPager的数据时,需要注意,设置默认开始的页面是第一个页面0。
当ViewPager滑动到最后一个页面0时就通过setCurrentItem(int item,boolean smoothScroll)方法将页面切换到第一个页面0处。同理当滑动到第一个页面2时,通过该方法将页面切换到第二个页面2,这样给我们的感觉就是无限循环。
① 操作步骤
在 PagerAdapter的getCount 方法中设置 返回值 是想要显示的页面数量 + 2。
在 PagerAdapter的instantiateItem 方法中对 position 进行相关判断更改,以显示正确的内容。
使用 setCurrentItem 方法,设置 显示的页面 是 第二个 页面。
通过在监听滚动方法的 onPageSelected 判断有没有滑动到左右添加的两个页面,如果滑到到了,需要使用 setCurrentItem 移动到该页面对应的真正页面处。
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 public class MainActivity extends AppCompatActivity { private int [] resources = {R.drawable.pic_1,R.drawable.pic_2,R.drawable.pic_3}; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ViewPager viewPager = findViewById(R.id.pager); viewPager.setAdapter(new PagerAdapter() { @Override public int getCount () { return resources.length + 2 ; } @Override public boolean isViewFromObject (@NonNull View view, @NonNull Object object) { return object == view; } @NonNull @Override public Object instantiateItem (@NonNull ViewGroup container, int position) { int realPosition; if (position == 0 ) { realPosition = resources.length - 1 ; } else if (position == resources.length + 2 - 1 ) { realPosition = 0 ; } else { realPosition = position - 1 ; } View inflate = LayoutInflater.from(getApplicationContext()).inflate(R.layout.pager_layout, null ); ImageView imageView = inflate.findViewById(R.id.image_view); imageView.setBackgroundResource(resources[realPosition]); container.addView(inflate); return inflate; } @Override public void destroyItem (@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView((View) object); } }); viewPager.setCurrentItem(1 ); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected (int position) { if (position == 0 ){ viewPager.setCurrentItem(resources.length,false ); }else if (position == resources.length+1 ){ viewPager.setCurrentItem(1 ,false ); } } @Override public void onPageScrollStateChanged (int state) { } }); } }
② 运行效果
③ 上面移动位置的操作是在 onPageSelected 方法中执行,该方法是已经滑动到该页面后才开始调用,我们可以看到有一点点的生硬。如果我们放在 onPageScrollStateChanged 方法中 滑动结束的时候移动位置就看不到生硬的效果了。
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 public class MainActivity extends AppCompatActivity { private int [] resources = {R.drawable.pic_1,R.drawable.pic_2,R.drawable.pic_3}; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ViewPager viewPager = findViewById(R.id.pager); viewPager.setAdapter(new PagerAdapter() { @Override public int getCount () { return resources.length + 2 ; } @Override public boolean isViewFromObject (@NonNull View view, @NonNull Object object) { return object == view; } @NonNull @Override public Object instantiateItem (@NonNull ViewGroup container, int position) { int realPosition; if (position == 0 ) { realPosition = resources.length - 1 ; } else if (position == resources.length + 2 - 1 ) { realPosition = 0 ; } else { realPosition = position - 1 ; } View inflate = LayoutInflater.from(getApplicationContext()).inflate(R.layout.pager_layout, null ); ImageView imageView = inflate.findViewById(R.id.image_view); imageView.setBackgroundResource(resources[realPosition]); container.addView(inflate); return inflate; } @Override public void destroyItem (@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView((View) object); } }); viewPager.setCurrentItem(1 ); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { int currentPosition = 0 ; @Override public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected (int position) { currentPosition = position; } @Override public void onPageScrollStateChanged (int state) { if (state == ViewPager.SCROLL_STATE_IDLE){ if (currentPosition == 0 ){ viewPager.setCurrentItem(resources.length,false ); }else if (currentPosition == resources.length+1 ){ viewPager.setCurrentItem(1 ,false ); } } } }); } }
参考文章 ViewPager两种方式实现无限轮播
ViewPager实现无限循环的2种方法