您的位置:首页 > 移动开发 > Android开发

Android中级:轮播图(一):实现ViewPager的无线自动循环

2016-08-23 01:10 489 查看
无限自动循环 = 无限循环 + 自动循环
无限循环 = 无限向左循环 + 无限向右循环
向左:图片由;右向左滑动
向右:图片由右向左滑动




接下来我们通过demo一步步的实现无限向右循环–>无限向左循环–>自动循环

Demo中viewpager中放有5张图片,我们可以向左向右滑动,但是

若当前页是第一页,则无法再向右滑动。

若当前页是最后一页,则无法再向左滑动。

一般情况:没有循环,需手滑

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1A237E"
tools:context=".MainActivity" >

<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_centerInParent="true" />

</RelativeLayout>


MainActivity.java

public class MainActivity extends Activity {

protected static final String tag = "MainActivity";
private ViewPager viewpager;
private List<ImageView> imageList = new ArrayList<ImageView>();
private Context context;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
initData();
viewpager = (ViewPager) findViewById(R.id.viewpager);
viewpager.setAdapter(new MyAdapter());
}

private void initData() {
imageList.clear();
ImageView iva = new ImageView(context);
iva.setBackgroundResource(R.drawable.a);

ImageView ivb = new ImageView(context);
ivb.setBackgroundResource(R.drawable.b);

ImageView ivc = new ImageView(context);
ivc.setBackgroundResource(R.drawable.c);

ImageView ivd = new ImageView(context);
ivd.setBackgroundResource(R.drawable.d);

ImageView ive = new ImageView(context);
ive.setBackgroundResource(R.drawable.e);

imageList.add(iva);
imageList.add(ivb);
imageList.add(ivc);
imageList.add(ivd);
imageList.add(ive);
}

public class MyAdapter extends PagerAdapter{
//表示viewpager共存放了多少个页面
@Override
public int getCount() {
return imageList.size();
}

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

@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(imageList.get(position));
return imageList.get(position);
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
}
}


添加无限向左循环

可以无限次的向左滑动,需要对PagerAdapter的2个方法进行修改

return Integer.MAX_VALUE:viewpager里面有几乎无穷多个object
imageList.get(position % imageList.size());防止角标越界


//表示viewpager共存放了多少个页面
@Override
public int getCount() {
return Integer.MAX_VALUE;//我们设置viewpager中有Integer.MAX_VALUE个页面
}


/**
* position % imageList.size() 而不是position,是为了防止角标越界异常
* 因为我们设置了viewpager子页面的数量有Integer.MAX_VALUE,而imageList的数量只是5。
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(imageList.get(position % imageList.size()));
return imageList.get(position % imageList.size());
}


但是这样暴露一个缺点,就是可以向左滑动,但是当前页是第一页的时候,无法向右滑动,因为第一页的position是0。

解决方法:
给viewpager设置当前页是第1000页,这样当前页的左边还有999页,右边还有Integer.MAX_VALUE - 1000页,
无论是999,还是(Integer.MAX_VALUE - 1000),一般情况下是滑不到第一页或最后一页的。
当然1000是自己设置的,也可以设置多加几个0。


添加无限向右循环

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
initData();
viewpager = (ViewPager) findViewById(R.id.viewpager);
viewpager.setAdapter(new MyAdapter());
viewpager.setCurrentItem(1000);//当前页是第1000页
}


添加自动循环

上面只是实现了无限循环,但还是用手动的,我们需要它每个一段时间(2秒)滑动一次。这就需要用到handler

int msgWhat = 0;
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);//收到消息,指向下一个页面
handler.sendEmptyMessageDelayed(msgWhat, 2000);//2S后在发送一条消息,由于在handleMessage()方法中,造成死循环。
Log.d(tag, "handleMessage");
};
};


同时在onCreat()方法中发送消息:handler.sendEmptyMessageDelayed(msgWhat, 2000);


出现的bug

Bug1:内存泄露

Bug:虽然我们实现了 无限自动循环功能,但当我们由MainActivity调转到SecondActivity的时候,通过Log.d(tag, “handleMessage”);发现handler还在发送消息,这就是内存泄露,所以我们需要在ManiActivity不可见不可交互的时候移除message。

解决方法:在onStop()里移除message


/**
* 当MainActivity不可见的时候让handler停止发送消息
* 防止内存泄露
*/
@Override
protected void onStop() {
super.onStop();
handler.removeMessages(msgWhat);
}


Bug2:再次回到 当前页,viewpager不再自动循环

由于我们把handler.sendEmptyMessageDelayed(msgWhat, 2000);写在了onCreate(),当我们由MainActivity调转到SecondActivity的时候,在回来MainActivity的时候,MainActivity并没有被销毁,onCreate()方法并不会再执行。

解决方法:写在onResume()里面


/**
* activity可见可交互的时候就开始发送消息,开启循环
*/
@Override
protected void onResume() {
super.onResume();
handler.sendEmptyMessageDelayed(msgWhat, 2000);
}


所以,最后的完整代码是:

public class MainActivity extends Activity {

protected static final String tag = "MainActivity";
private ViewPager viewpager;
private List<ImageView> imageList = new ArrayList<ImageView>();
private Context context;
int msgWhat = 0; private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);//收到消息,指向下一个页面 handler.sendEmptyMessageDelayed(msgWhat, 2000);//2S后在发送一条消息,由于在handleMessage()方法中,造成死循环。 Log.d(tag, "handleMessage"); }; };
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
initData();
viewpager = (ViewPager) findViewById(R.id.viewpager);
viewpager.setAdapter(new MyAdapter());
viewpager.setCurrentItem(1000);//当前页是第1000页

// Button只是为了验证内存泄露
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Intent intent = new Intent(context, SecondActivity.class);
startActivity(intent);
}
});
}

private void initData() {
imageList.clear();
ImageView iva = new ImageView(context);
iva.setBackgroundResource(R.drawable.a);

ImageView ivb = new ImageView(context);
ivb.setBackgroundResource(R.drawable.b);

ImageView ivc = new ImageView(context);
ivc.setBackgroundResource(R.drawable.c);

ImageView ivd = new ImageView(context);
ivd.setBackgroundResource(R.drawable.d);

ImageView ive = new ImageView(context);
ive.setBackgroundResource(R.drawable.e);

imageList.add(iva);
imageList.add(ivb);
imageList.add(ivc);
imageList.add(ivd);
imageList.add(ive);
}

public class MyAdapter extends PagerAdapter{
//表示viewpager共存放了多少个页面 @Override public int getCount() { return Integer.MAX_VALUE;//我们设置viewpager中有Integer.MAX_VALUE个页面 }

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

/** * position % imageList.size() 而不是position,是为了防止角标越界异常 * 因为我们设置了viewpager子页面的数量有Integer.MAX_VALUE,而imageList的数量只是5。 */ @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(imageList.get(position % imageList.size())); return imageList.get(position % imageList.size()); }

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
}

/** * activity可见可交互的时候就开始发送消息,开启循环 */ @Override protected void onResume() { super.onResume(); handler.sendEmptyMessageDelayed(msgWhat, 2000); }

/** * 当MainActivity不可见的时候让handler停止发送消息 * 防止内存泄露 */ @Override protected void onStop() { super.onStop(); handler.removeMessages(msgWhat); }
}


也可以不使用`Integer.MAX_VALUE`,还是以前的


@Override

public int getCount() {

return imgsList.size();

// return Integer.MAX_VALUE;

}

```
int index = (viewPager.getCurrentItem() + 1) % imgsList.size();
viewPager.setCurrentItem(index);


“`

源码

ViewPager无线自动循环

这样我们就实现了viewpager的自动无限循环功能,而且手动向左滑、向右滑都可以,接下来我们添加indicator。


Android中级:轮播图(二):实现indicator。地址:http://blog.csdn.net/ss1168805219/article/details/52294657
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: