目前情况

在不修改源码的情况下,当ViewPager滑动到最后一个item的时候,他就无法再往右滑动;当ViewPager滑动到第一个item的时候,他也无法再往前滑动。(以上全是废话)

设想

我们可以这样想,当滑动最后一个的时候,我们让他跳转到第一个,这样他就可以继续往后滑动了,这样做行程了我们想要的循环滑动。

如果这样作,虽然功能上是循环了,但是实际显示的时候会在最后一个和第一个之间自动跳转。

优化

我们可以在原来的链表中首尾各增加一个假的item,用多余的两个item来作跳转的动作,这样就可以避免出现自动跳转的错误画面了。请看下面演示。

我们要显示的是下面A、B、C画面,位置分别是0、1、2.

实际上,我们添加数据的时候,多添加了2个。在位置0添加了最后一个界面C,在位置4添加了第一个界面A。

当界面滑动到位置3的时候,他还可以往右滑动,这样给人的感觉就是循环的。但,当滑动到位置4的时候,他右边没有了,这样岂不是露馅了?所以,当滑动到位置4的时候,立刻跳转到位置1。因为他们是同样的数据,所以从显示效果是看不出跳转了的,这样实际上我们就变成了位置1,这样就又可以继续往右滑动了。

重复上面条件的判断,这样就实现了往右的循环,往左也是同样的道理。

代码分析

在onPageSelected里面做条件判断,在onPageScrollStateChanged里面做跳转。关键代码如下:

初始化,首尾各增加一个item。

  1. // 增加第1个界面,实际上他显示的是最后一个界面
  2. addTextView(POINT_LENGTH - 1);
  3. // 增加实际显示的2、3、4界面
  4. for (int i = 0; i < 3; i++) {
  5. addTextView(i);
  6. addPoint(i);
  7. }
  8. // 增加最后的第5个界面,实际上他显示的是第一个界面
  9. addTextView(0);

条件判断:

  1. @Override
  2. public void onPageSelected(int pPosition) {
  3. mIsChanged = true;
  4. if (pPosition > POINT_LENGTH) {
  5. mCurrentPagePosition = FIRST_ITEM_INDEX;
  6. } else if (pPosition < FIRST_ITEM_INDEX) {
  7. mCurrentPagePosition = POINT_LENGTH;
  8. } else {
  9. mCurrentPagePosition = pPosition;
  10. }
  11. Log.i(TAG,"当前的位置是"+mCurrentPagePosition);
  12. setCurrentDot(mCurrentPagePosition);
  13. }

跳转:

  1. @Override
  2. public void onPageScrollStateChanged(int pState) {
  3. if (ViewPager.SCROLL_STATE_IDLE == pState) {
  4. if (mIsChanged) {
  5. mIsChanged = false;
  6. mViewPager.setCurrentItem(mCurrentPagePosition, false);
  7. }
  8. }
  9. }

完整的逻辑如下:

  1. package com.ahacool.circleviewpager;
  2. import java.util.ArrayList;
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.support.v4.view.PagerAdapter;
  6. import android.support.v4.view.ViewPager;
  7. import android.support.v4.view.ViewPager.OnPageChangeListener;
  8. import android.util.Log;
  9. import android.view.Gravity;
  10. import android.view.View;
  11. import android.view.ViewGroup;
  12. import android.widget.ImageView;
  13. import android.widget.LinearLayout.LayoutParams;
  14. import android.widget.TextView;
  15. /**
  16. * @ClassName MainActivity
  17. * @Description 循环滑动viewpager的一种方法,滑动很流畅。实现方法:在实际显示的界面头和尾分别增加一个界面。
  18. * @author Moto
  19. * @date 2014 2014-7-18
  20. *
  21. */
  22. public class MainActivity extends Activity implements OnPageChangeListener {
  23. private ViewPager mViewPager;
  24. private ViewGroup mPointViewGroup;
  25. private ArrayList<View> mViewPagerList;
  26. private boolean mIsChanged = false;
  27. private int mCurrentPagePosition = FIRST_ITEM_INDEX;
  28. private int mCurrentIndex;
  29. private static final int POINT_LENGTH = 3;
  30. private static final int FIRST_ITEM_INDEX = 1;
  31. private static final String TAG = "MOTO";
  32. @Override
  33. protected void onCreate(Bundle savedInstanceState) {
  34. super.onCreate(savedInstanceState);
  35. setContentView(R.layout.activity_main);
  36. initUI();
  37. }
  38. private void initUI() {
  39. mViewPager = (ViewPager) findViewById(R.id.viewpager);
  40. mPointViewGroup = (ViewGroup) findViewById(R.id.point_layout);
  41. mViewPagerList = new ArrayList<View>();
  42. // 增加第1个界面,实际上他显示的是最后一个界面
  43. addTextView(POINT_LENGTH - 1);
  44. // 增加实际显示的2、3、4界面
  45. for (int i = 0; i < 3; i++) {
  46. addTextView(i);
  47. addPoint(i);
  48. }
  49. // 增加最后的第5个界面,实际上他显示的是第一个界面
  50. addTextView(0);
  51. PagerAdapter pagerAdapter = new CustomPagerAdapter(mViewPagerList);
  52. mViewPager.setAdapter(pagerAdapter);
  53. mViewPager.setOnPageChangeListener(this);
  54. mViewPager.setCurrentItem(mCurrentPagePosition, false);
  55. }
  56. private void addTextView(int pIndex) {
  57. TextView textview = new TextView(this);
  58. textview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
  59. textview.setGravity(Gravity.CENTER);
  60. textview.setText("这是第" + (pIndex + 1) + "个页面");
  61. textview.setTextSize(50);
  62. mViewPagerList.add(textview);
  63. }
  64. private void addPoint(int pIndex) {
  65. ImageView pointImageView = new ImageView(this);
  66. LayoutParams layoutParams = new LayoutParams(20, 20);
  67. layoutParams.setMargins(10, 0, 10, 0);
  68. pointImageView.setLayoutParams(layoutParams);
  69. pointImageView.setBackgroundResource(R.drawable.point_style);
  70. if (0 == pIndex) {
  71. pointImageView.setEnabled(false);
  72. }
  73. mPointViewGroup.addView(pointImageView);
  74. }
  75. private void setCurrentDot(int positon) {
  76. // 界面实际显示的序号是第1, 2, 3。而点的序号应该是0, 1, 2.所以减1.
  77. positon = positon - 1;
  78. if (positon < 0 || positon > mViewPagerList.size() - 1 || mCurrentIndex == positon) {
  79. return;
  80. }
  81. mPointViewGroup.getChildAt(positon).setEnabled(false);
  82. mPointViewGroup.getChildAt(mCurrentIndex).setEnabled(true);
  83. mCurrentIndex = positon;
  84. }
  85. @Override
  86. public void onPageScrollStateChanged(int pState) {
  87. if (ViewPager.SCROLL_STATE_IDLE == pState) {
  88. if (mIsChanged) {
  89. mIsChanged = false;
  90. mViewPager.setCurrentItem(mCurrentPagePosition, false);
  91. }
  92. }
  93. }
  94. @Override
  95. public void onPageScrolled(int arg0, float arg1, int arg2) {
  96. }
  97. @Override
  98. public void onPageSelected(int pPosition) {
  99. mIsChanged = true;
  100. if (pPosition > POINT_LENGTH) {
  101. mCurrentPagePosition = FIRST_ITEM_INDEX;
  102. } else if (pPosition < FIRST_ITEM_INDEX) {
  103. mCurrentPagePosition = POINT_LENGTH;
  104. } else {
  105. mCurrentPagePosition = pPosition;
  106. }
  107. Log.i(TAG,"当前的位置是"+mCurrentPagePosition);
  108. setCurrentDot(mCurrentPagePosition);
  109. }
  110. }

源码下在地址:https://github.com/bird7310/Demos.git

总结

希望对大家有帮助,多提意见。近段时间项目很赶,很长时间没看书写博客了。赶项目赶得都麻木了,放松放松,偷偷懒,写写博客吧。

无限循环的ViewPager的更多相关文章

  1. android 无限循环的viewpager

    思路 例如存在 A -B -C 需要在viewpager滑动时无限循环 1.我们可以设计 C' A B C A'  C'与C相同,A'与A相同 2.滑动到A'时,则index回到1 3.滑动到C'时, ...

  2. [android] 轮播图-无限循环

    实现无限循环 在getCount()方法中,返回一个很大的值,Integer.MAX_VALUE 在instantiateItem()方法中,获取当前View的索引时,进行取于操作,传递进来的int ...

  3. 详细分析Android viewpager 无限循环滚动图片

    由于最近在忙于项目,就没时间更新博客了,于是趁着周日在房间把最近的在项目中遇到的技术总结下.最近在项目中要做一个在viewpager无限滚动图片的需求,其实百度一下有好多的例子,但是大部分虽然实现了, ...

  4. 一行代码引入 ViewPager 无限循环 + 页码显示

    (出处:http://www.cnblogs.com/linguanh) 前序: 网上的这类 ViewPager 很多,但是很多都不够好,体现在 bug多.对少页面不支持,例如1~2张图片.功能整合不 ...

  5. ViewPager,实现真正的无限循环(定时+手动)

    利用定时器,实现循环轮播,很简单:只需在定时器的消息里加如下代码即可: int count = adapter.getCount(); if (count > 1) { // 多于1个,才循环 ...

  6. 扩展ViewFlow避免和ViewPager滑动冲突,同时支持无限循环,并完美和CircleFlowIndicator结合

    首先,为了避免滑动冲突,我们要继承ViewFlow,重写onInterceptTouchEvent public class MyViewFlow extends ViewFlow { private ...

  7. 自定义完美的ViewPager 真正无限循环的轮播图

    网上80%的思路关于Android轮播图无限循环都是不正确的,不是真正意义上的无限循环, 其思路大多是将ViewPager的getCount方法返回值设置为Integer.MAX_VALUE, 然后呢 ...

  8. android 自定义无限循环播放的viewPager。轮播ViewPager。实现循环播放 广告,主题内容,活动,新闻内容时。

    前言 实际项目需要一个 播放广告的控件,可能有多个广告图片.每个一段时间更换该图片.简单来说,就是一个 “循环播放图片”的控件. 间隔时间更换图片 一般来说,图片切换时需要有动画效果 需要支持手势,用 ...

  9. ViewPager 无限循环

    Overview 我们在使用ViewPager来制作图片轮播的时候,常常为ViewPager不能一直无限循环的问题所苦恼.对于这个问题,目前从网上找到了两个思路来解决: 将 ViewPager 的Co ...

随机推荐

  1. CSS 布局Float 【3】

    float 属性定义元素在哪个方向浮动. 浮动元素会生成一个块级框,而不论它本身是何种元素. 如果浮动非替换元素,则要指定一个明确的宽度:否则,它们会尽可能地窄. 注释:假如在一行之上只有极少的空间可 ...

  2. js apply

    1.作用 函数的apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数.唯一的区别就是,它接收一个数组作为函数执行时的参数 Fn.apply(obj, [arg1, arg2, ...

  3. Neutron/ML2学习

    Neutron/ML2 Neutron ML2 模块层2(ml2)插件是一种允许OpenStack网络同时地利用在复杂现实数据中心发现的各种第二层网络技术的框架.目前它与存在的openvswitch. ...

  4. Java学习-----单例模式

    一.问题引入 偶然想想到的如果把Java的构造方法弄成private,那里面的成员属性是不是只有通过static来访问呢:如果构造方法是private的话,那么有什么好处呢:如果构造方法是privat ...

  5. underscorejs-pluck学习

    2.14 pluck 2.14.1 语法: _.pluck(list, key) 2.14.2 说明: pluck方法根据key对list数组中的每个对象进行检索,返回检索成功的属性值,否则返回und ...

  6. 初涉JavaScript模式 (7) : 原型模式 【三】

    组合使用构造函数模式和原型模式 上篇,我们提到了原型模式的缺点,就是每个实例不能拥有自己的属性,因为纯原型模式所有的属性都是公开给每个实例的,故我们可以组合使用构造函数模式和原型模式.构造函数用来定义 ...

  7. 如何去除 ckeditor 上传图片后在原码中留下的 style="width: 100%;height:100px"之类的代码呢?

    ckeditor编辑器在上传图片的时候,会神奇的加上一段诡异的代码: 这导致上传的小图也是被拉伸到100%,我根本就没有定义它,找来找去也找不到element.style,原来这是在system.cs ...

  8. UI基础 - UINavigationController

    如果导航控制器的BarButtonItem属性是一致的,可以重写initialize方法用来设置主题 //再ViewDidload执行前只执行一次 +(void)initialize { //创建的U ...

  9. MFC一个令人纠心的错误

    IDE生成的代码,运行几次之后开始出现以下这个错误 Error: must call SetScrollSizes() or SetScaleToFitSize() before painting s ...

  10. Lambert

    Dmap -- 贴图信息 LightColor  -- 灯光颜色 KL -- 灯光强度值(开放给美术) EnvColor -- 环境颜色 ka -- 环境光强度 (开放给美术) Dmap * (max ...