对于经常使用viewpager的人,应该清楚一般的viewpager在滑动到最右端或者最左端时,就不能继续往下滑动了,从用户的角度来看,这点的体验很不好,用户可能期待的是当我滑动到最后一页的时候,可以继续滑动,并滑动到第一页,所以我们需要实现viewpager的循环滑动。在网上也找了很多例子,基本上比较实用的方法就是一种,这个我们后边就是讲这种方法,并且在此基础上添加了可以控制viewpager是否需要自动循环滑动的功能,先上效果图:
接下来,我们来分析实现的方法:
假如说我们的viewpager中现在有三张图片A, B, C, 要实现滑动的C的时候,我们能继续滑动并且滑动到A,网上的方法是在viewpager最开始的位置插入最后一张图片C,在viewpager最后的位置插入最开始的图片A,这样,我们viewpager中的图片就变为C, A, B, C, A。当我们滑动最后一张C的时候,这个时候在滑动的话,是可以继续滑动的,因为C后边还有一个A,但是当滑动完成后,需要将下标为4的A改为下标为1的A,这样后,当A在滑动到它的下一页时才会出现B,否则将不能继续向右滑动(因为此时的A已经是viewpager中的最后一个了)。向左滑动是一样的道理。
接下来,就是上代码,先来看我们自定义的viewpager类(这是网上的类,我只是修改了一下):
package com.example.test_loop_viewpager;
import android.content.Context;
import android.database.DataSetObserver;
import android.os.Handler;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class CycleViewPager extends ViewPager {
private InnerPagerAdapter mAdapter;
private int mCurrentIndex = 1;
//播放标志
private boolean isPlay = false;
private final int PLAY = 0x123;
//默认页面之间的切换时间
private long mDelayTime = 2000;
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
if (msg.what == PLAY){
setCurrentItem(mCurrentIndex);
if (isPlay){
play();
}
}
}
};
public CycleViewPager(Context context) {
super( context);
setOnPageChangeListener( null);
}
public CycleViewPager(Context context, AttributeSet attrs) {
super( context, attrs);
setOnPageChangeListener( null);
}
@Override
public void setAdapter(PagerAdapter arg0) {
mAdapter = new InnerPagerAdapter( arg0);
super.setAdapter( mAdapter);
setCurrentItem(1);
}
/**
* 开始播放
* @param delayMillis
*/
public void startPlay( long delayMillis){
isPlay = true;
mDelayTime = delayMillis;
play();
}
private void play(){
mCurrentIndex ++;
mCurrentIndex = mCurrentIndex % mAdapter.getCount();
if (mCurrentIndex == 0){
mCurrentIndex += 2;
}
mHandler.sendEmptyMessageDelayed(PLAY, mDelayTime);
}
/**
* 停止播放
*/
public void stopPlay(){
isPlay = false;
}
@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
super.setOnPageChangeListener( new InnerOnPageChangeListener( listener));
}
private class InnerOnPageChangeListener implements OnPageChangeListener {
private OnPageChangeListener listener;
private int position;
public InnerOnPageChangeListener(OnPageChangeListener listener) {
this.listener = listener;
}
@Override
public void onPageScrollStateChanged(int arg0) {
if(null != listener) {
listener.onPageScrollStateChanged( arg0);
}
if(arg0 == ViewPager.SCROLL_STATE_IDLE) {
if(position == mAdapter.getCount() - 1) {
setCurrentItem( 1, false);
}
else if(position == 0) {
setCurrentItem(mAdapter.getCount() - 2, false);
}
}
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
if(null != listener) {
listener.onPageScrolled( arg0, arg1, arg2);
}
}
@Override
public void onPageSelected(int arg0) {
mCurrentIndex = arg0;
position = arg0;
if(null != listener) {
listener.onPageSelected( arg0);
}
}
}
private class InnerPagerAdapter extends PagerAdapter {
private PagerAdapter adapter;
public InnerPagerAdapter(PagerAdapter adapter) {
this.adapter = adapter;
adapter.registerDataSetObserver( new DataSetObserver() {
@Override
public void onChanged() {
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
notifyDataSetChanged();
}
});
}
@Override
public int getCount() {
return adapter.getCount() + 2;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return adapter.isViewFromObject( arg0, arg1);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if(position == 0) {
position = adapter.getCount() - 1;
}
else if(position == adapter.getCount() + 1) {
position = 0;
}
else {
position -= 1;
}
return adapter.instantiateItem( container, position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
adapter.destroyItem( container, position, object);
}
}
}
这个类里有两个内部类,InnerOnPageChangeListener和InnerPagerAdapter, 这两个内部类是对我们传进来的onPagerChangeListener和PagerAdapter做了一下包装,且处理了一些我们自己的逻辑业务。并且提供了两个接口startPaly(long delayMillis)和stopPlay()来播放图片和停止播放,一般我们在onResume()和onPause()方法调用这两个方法。
再来看给viewpager设置数据源的adapter类:
package com.example.test_loop_viewpager;
import android.content.Context;
import android.provider.MediaStore.Images.ImageColumns;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2016/2/2.
*/
public class MyPagerAdapter extends PagerAdapter {
private Context mContext;
private List<ImageView> mImageViewCache = new ArrayList<ImageView>();
private List<Integer> mImageUrl;
public MyPagerAdapter(Context context, List<Integer> imageUrl){
this.mContext = context;
mImageUrl = imageUrl;
}
@Override
public int getCount() {
return mImageUrl != null ? mImageUrl.size() : 0;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView iv = (ImageView) object;
container.removeView(iv);
mImageViewCache.add(iv);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView image = null;
if (mImageViewCache.isEmpty()){
image = new ImageView(mContext);
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
}else {
image = mImageViewCache.remove(0);
}
image.setImageResource(mImageUrl.get(position));
container.addView(image);
return image;
}
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
}
这个类没什么说的,跟我们平时写Viewpager时写的PagerAdapter一样
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.test_loop_viewpager.CycleViewPager
android:id="@+id/id_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.test_loop_viewpager.CycleViewPager>
</RelativeLayout>
在MainActivity中调用:
package com.example.test_loop_viewpager;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore.Images;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.Window;
import android.widget.ImageView;
public class MainActivity extends Activity {
private CycleViewPager mPager;
private MyPagerAdapter mPagerAdapter;
private List<Integer> mImages = new ArrayList<Integer>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mPager = (CycleViewPager) findViewById(R.id.id_pager);
setData();
mPagerAdapter = new MyPagerAdapter(this, mImages);
mPager.setAdapter(mPagerAdapter);
}
private void setData() {
mImages.add(R.drawable.image1);
mImages.add(R.drawable.image2);
mImages.add(R.drawable.image3);
mImages.add(R.drawable.image4);
mImages.add(R.drawable.image5);
}
@Override
protected void onResume() {
mPager.startPlay(2000);
super.onResume();
}
@Override
protected void onPause() {
mPager.stopPlay();
super.onPause();
}
}
到此,基本上就完成了Viewpager的循环滑动和自动播放功能,还有一些小细节的东西没有加,如果说提示点什么的, 大家可以自行添加。