ViewPager使用总结之无限循环(完美实现:更正)

2021年9月9日 3点热度 0条评论 来源: lue2009

我们在对ViewPager进行滑动操作的时候,当拖动到最左边或最右边的时候,想继续向右拖动查看上一页或继续向左查看下一页的时候,是拖动不了的;为了提高用户体验,我们需要循环浏览这些页面,那么就需要循环拖动;我在网上找了许多ViewPager做成无限循环的资料不是左右拖动出现空白的问题就是View没有回收

以下是我的分析思路:

(1)无限循环是有条件的,ViewPager里面的数据至少是两条,只有一条数据做成无限循环没什么意义。

(2)我们知道ViewPager多少页面取决于对应多少条数据,默认情况下PagerAdapter中getCount返回的值对应数据个数,正因为这样,每次当我们滑动页面的时候,都会触发调用getCount方法,之所以拖动不了ViewPager内部估计是对当前显示的位置和getCount进行了比较判断判断,那么我们可以使getCount返回的值足够大(return Integer.MAX_VALUE),这样就能一直拖动下去

(3) 由于每次滑动操作的时候ViewPager会将距离当前位置2个步幅或以上的view清除掉的,

     还有ViewPager最多管理3个View,为了确保在左右滑动的时候不会出现空白页面,

     那么我们至少要保证PagerAdapter的子类里面的数据至少是4条,这样就能保证ViewPager

     始终存在3个View。如何保证数据至少是4条呢?如果数据个数少于4,就需要追加重复数据直到有4条,如果数据个数不少于4,      那么不用追加

(4) 保证数据的连贯性以及和页面的对应关系

     Eg:  如果有2条数据A,B,position = 0, position = 1分别对应数据A 和 B

        ------+---+---+---+------
         ... | A | B| 
       ------+---+---+---+------

      假如当前position=1,对应数据B,再继续向左滑动查看下一个页面,那么下个页面对应的数据应该是A,

      那么需要追加2条数据,A,B ,这样就构成了闭循环(A,B,A,B), 数据是连贯的。

      

如果有3条数据A,B,C ,position = 0, position = 1,position = 2分别对应数据A , B和 C,此时如果仅仅是为了凑满4条数据,只加一条数据 A, 那么添加后的总数据 A,B,C A 数据不是连贯的,所以此时需要追加3条 A,B,C,这样就构成了闭循环(A,B,C,A,B,C)


以上的分析全部都是针对PagerAdapter的子类进行做文章,具体实现代码如下:

(1) 为了便于可重用,我这里将PagerAdapter的子类进行了抽象

public abstract class AbstractViewPagerAdapter<T> extends PagerAdapter
{
	protected List<T> mData;
	private SparseArray<View> mViews;
	protected Context mContext;

	protected boolean hasAppend;
	protected int appendCounts;
	
	private String TAG = "AbstractViewPagerAdapter";

	private int count;
	
	public AbstractViewPagerAdapter(List<T> data,Context context)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>mData = data;
<span style="white-space:pre">		</span>mContext = context;
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>int size = mData.size();
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>if(size > 1 && size <4)
<span style="white-space:pre">		</span>{//
<span style="white-space:pre">			</span>int aftAddSize = 4;
<span style="white-space:pre">			</span>Object[] appendDatas =  null;
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>if(size  == 2)
<span style="white-space:pre">			</span>{<span style="white-space:pre">	</span>//追加到4条,保证数据循环eg:A,B --> A,B,A,B
<span style="white-space:pre">				</span>aftAddSize = 4;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>else if(size  == 3)
<span style="white-space:pre">			</span>{<span style="white-space:pre">	</span>//追加到6条,保证数据循环,A,B,C --> A,B,C,A,B,C
<span style="white-space:pre">				</span>aftAddSize = 6;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>appendDatas = new Object[aftAddSize-size];
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>for(int i=0; i<(aftAddSize-size); i++)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>appendDatas[i] = mData.get(i%size);
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>for(int i=0; i<(aftAddSize-size); i++)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>mData.add((T)appendDatas[i]);
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>
<span style="white-space:pre">			</span>mViews = new SparseArray<View>(aftAddSize);
<span style="white-space:pre">			</span>appendCounts = aftAddSize-size;
<span style="white-space:pre">			</span>hasAppend = true;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>else
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>mViews = new SparseArray<View>(data.size());<span style="white-space:pre">	</span>
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}

	@Override
	public int getCount()
	{
               if(mData.size() <= 1)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>return mData.size();
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>else
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>return Integer.MAX_VALUE;
<span style="white-space:pre">		</span>}
	}

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

	@Override
	public Object instantiateItem(ViewGroup container, int position)
	{
		
		int size = mData.size();

		int realPos = position % size;
		
		Log.d(TAG, "instantiateItem,position="+position+",realPos="+realPos);
		
		View view = mViews.get(realPos);
		if (view == null)
		{
			view = newView(realPos);
			mViews.put(realPos, view);
		}

		try
		{
			container.addView(view);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		Log.d(TAG, "instantiateItem,current container.childCount="+container.getChildCount());
		return view;
	}

	public abstract View newView(int position);

	@Override
	public void destroyItem(ViewGroup container, int position, Object object)
	{
		int size = mData.size();
		int realPos = position % size;
		
		Log.d(TAG, "destroyItem,position="+position+",realPos="+realPos);
		
		Log.d(TAG, "destroyItem,before destroyItem current container.childCount="+container.getChildCount());
		
		container.removeView(mViews.get(realPos));
		
		Log.d(TAG, "destroyItem,after destroyItem current container.childCount="+container.getChildCount());
	}

	public T getItem(int position)
	{
		int size = mData.size();
		if (hasAppend)
		{
			size = size - appendCounts;
		}
		int realPos = position % size;
		return mData.get(realPos);
	}
}

(2) 抽象类的实现类

public class MyPagerAdapter extends AbstractViewPagerAdapter<Integer>
{
	public MyPagerAdapter(List<Integer> datas,Context context)
	{
		super(datas,context);
	}
		
	@Override
	public View newView(int position)
	{
		ImageView img = new ImageView(mContext);
		
		ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,80);
		img.setLayoutParams(params);
		
		img.setImageResource(mData.get(position));
		return img;
	}
}

上面MyPagerAdapter 放的数据是图片资源ID列表。根据项目实际需要,AbstractViewPagerAdapter<T> 用实际的数据

(3)XML文件声明ViewPager

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:orientation="vertical" >  
      
   <android.support.v4.view.ViewPager    
        android:id="@+id/viewPager"    
        android:layout_width="fill_parent"    
        android:layout_height="wrap_content" />   
          
    <RelativeLayout    
        android:layout_width="fill_parent"    
        android:layout_height="wrap_content"   
        android:orientation="vertical" >
        <!-- 存放进度点 -->
        <LinearLayout    
            android:id="@+id/viewGroup"    
            android:layout_width="fill_parent"    
            android:layout_height="wrap_content"    
            android:layout_alignParentBottom="true"   
            android:layout_marginBottom="30dp"    
            android:gravity="center_horizontal"    
            android:orientation="horizontal" >    
        </LinearLayout>    
    </RelativeLayout>
</FrameLayout>

(4) Activity中完成初始化

public class TestViewPager extends Activity
{
	ViewPager viewPager;

	ImageView[] tips;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_testviewpager);

		ViewGroup group = (ViewGroup) findViewById(R.id.viewGroup);
		
		viewPager = (ViewPager) findViewById(R.id.viewPager);

		List<Integer> resIdLst = new ArrayList<Integer>();
		resIdLst.add(R.drawable.item01);
		resIdLst.add(R.drawable.item02);
//		resIdLst.add(R.drawable.item03);
//		resIdLst.add(R.drawable.item04);
//		resIdLst.add(R.drawable.item05);
//		resIdLst.add(R.drawable.item06);
//		resIdLst.add(R.drawable.item07);
//		resIdLst.add(R.drawable.item08);

		int len = resIdLst.size();
		tips = new ImageView[len];

		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(20, 20);
		params.leftMargin = 5;
		params.rightMargin = 5;
		
		for (int i = 0; i < len; i++)
		{
			ImageView img = new ImageView(this);
			if (i == 0)
			{
				img.setBackgroundResource(R.drawable.ic_weekday_checked);
			}
			else
			{
				img.setBackgroundResource(R.drawable.ic_weekday_unchecked);
			}

			img.setLayoutParams(params);
			tips[i] = img;

			group.addView(img);
		}

		viewPager.setAdapter(new MyPagerAdapter(resIdLst, this));

		viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener()
		{
			@Override
			public void onPageSelected(int arg0)
			{
				// TODO Auto-generated method stub
				setImageBackground(arg0 % tips.length);
			}

			@Override
			public void onPageScrolled(int arg0, float arg1, int arg2)
			{
				// TODO Auto-generated method stub
			}

			@Override
			public void onPageScrollStateChanged(int arg0)
			{
				// TODO Auto-generated method stub

			}
		});

		// 设置ViewPager的默认项, 设置为长度的100倍,这样开始就能往左滑动
		viewPager.setCurrentItem((tips.length) * 100);//
	}

	private void setImageBackground(int selectItems)
	{
		int len = tips.length;
		for (int i = 0; i < len; i++)
		{
			if (i == selectItems)
			{
				tips[i].setBackgroundResource(R.drawable.ic_weekday_checked);
			}
			else
			{
				tips[i].setBackgroundResource(R.drawable.ic_weekday_unchecked);
			}
		}
	}
}

注意进度点的显示,要根据实际的数据个数,虽然追加后是4条数据,但是真正是2条数据,所以是两个进度点。

使用到的资源:
 

效果图如下:

    原文作者:lue2009
    原文地址: https://blog.csdn.net/lue2009/article/details/42422687
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。