[Android]无限循环ViewPager

来源:互联网 发布:linux 迅雷远程下载 编辑:程序博客网 时间:2024/04/28 21:51

首先,我们先来看看平常时,我们是如何使用ViewPager的。

布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?><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"    tools:context="com.xiaoyan.xiejinxiong.unlimitedslideviewpager.MainActivity">    <android.support.v4.view.ViewPager        android:id="@+id/viewpager"        android:layout_width="match_parent"        android:layout_height="match_parent" /></RelativeLayout>
适配器代码:MyViewPagerAdapter.java

package com.xiaoyan.xiejinxiong.unlimitedslideviewpager;import android.support.v4.view.PagerAdapter;import android.view.View;import android.view.ViewGroup;import java.util.List;/** * Created by xiejinxiong on 2016/6/3. */public class MyViewPagerAdapter extends PagerAdapter {    private List<View> mListViews;    public MyViewPagerAdapter(List<View> mListViews) {        this.mListViews = mListViews;    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        container.removeView(mListViews.get(position));//删除页卡    }    @Override    public Object instantiateItem(ViewGroup container, int position) {    //实例化页卡        container.addView(mListViews.get(position), 0);//添加页卡        return mListViews.get(position);    }    @Override    public int getCount() {        return mListViews.size();//返回页卡的数量    }    @Override    public boolean isViewFromObject(View arg0, Object arg1) {        return arg0 == arg1;//官方提示这样写    }}

主页面:MainActivity.java

package com.xiaoyan.xiejinxiong.unlimitedslideviewpager;import android.app.Activity;import android.support.v4.view.ViewPager;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.ImageView;import java.util.ArrayList;import java.util.List;/** * @author xiejinxiong */public class MainActivity extends Activity {    private ViewPager viewPager;    /**ViewPager适配器*/    private MyViewPagerAdapter myViewPagerAdapter;    /** 存储ViewPager需要显示的View */    private List<View> list;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initUI();    }    /**     * 初始化UI     */    private void initUI() {        viewPager = (ViewPager) findViewById(R.id.viewpager);        //初始化图片数据        list = new ArrayList<>();        ImageView imageView = new ImageView(this);        imageView.setImageResource(R.drawable.pic1);        list.add(imageView);        ImageView imageView2 = new ImageView(this);        imageView2.setImageResource(R.drawable.pic2);        list.add(imageView2);        ImageView imageView3 = new ImageView(this);        imageView3.setImageResource(R.drawable.pic3);        list.add(imageView3);        myViewPagerAdapter = new MyViewPagerAdapter(list);        viewPager.setAdapter(myViewPagerAdapter);    }}

由以上代码便可以制作一个可滑动,具有三个页面的ViewPager:



(- -没弄Gif,就勉强看看图片吧)

由上面的代码,我们可以很清楚的看出,布局文件与主页面的功能并不多,只是定义初始化ViewPager以及填充数据,具体对于ViewPager的页面加载操作大部分都需要在ViewPager的适配器中写,因此,假如我们想制作一个无限滑动的Viewpager,更多的也是在ViewPager的适配器中进行修改。

首先,我们先看看,为何这个ViewPager只能滑动三个页面?

    public int getCount() {        return mListViews.size();//返回页卡的数量    }
无疑,大部分原因出现在这里,因此,我们需要在这里进行修改,我们将其修改为一个最大值,那便是Integer.MAX_VALUE

    @Override    public int getCount() {        return Integer.MAX_VALUE;    }
然后,我们再对程序进行运行:

我们会发现,假如我们只是滑动前面两个是完全没有问题的,但是滑动到第三个就会报错:

                    java.lang.IndexOutOfBoundsException: Invalid index 3, size is 3                     at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)                     at java.util.ArrayList.get(ArrayList.java:304)                     at com.xiaoyan.xiejinxiong.unlimitedslideviewpager.MyViewPagerAdapter.instantiateItem(MyViewPagerAdapter.java:29)                     at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:943)                    at android.support.v4.view.ViewPager.populate(ViewPager.java:1157)                    at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)                   at android.support.v4.view.ViewPager$3.run(ViewPager.java:254)                   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)                    at android.view.Choreographer.doCallbacks(Choreographer.java:555)                   at android.view.Choreographer.doFrame(Choreographer.java:524)                    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)                    at android.os.Handler.handleCallback(Handler.java:615)                    at android.os.Handler.dispatchMessage(Handler.java:92)                     at android.os.Looper.loop(Looper.java:137)                     at android.app.ActivityThread.main(ActivityThread.java:4745)                     at java.lang.reflect.Method.invokeNative(Native Method)                      at java.lang.reflect.Method.invoke(Method.java:511)                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)                  at dalvik.system.NativeStart.main(Native Method)

那是因为我们设置geiCount()为无限大,也就是我们告诉ViewPager,我们具有着无限多个页面,因此当它滑动到第三个的时候,便开始预加载第四个,但mListViews.size()只有三个,因此报下标越界错误,错误在这行:

  container.addView(mListViews.get(position), 0);//添加页卡
因此,我们需要对该行进行修改:

mListViews.get(position),我们只是需要获得需要显示的View,也就是,当position为3的时候,我们需要获得mListViews.get(0)的View,当position为4的时候,我们需要获得mListViews.get(1)的View,以此类推,我们可以将该适配器中的mListViews.get(position)全部改为mListViews.get(position% mListViews.size()),运行:

由此,你可以一直向左划,是可以不断地滑动的,但是,假如你是向右划一下的话,就会报错:

 java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.    at android.view.ViewGroup.addViewInner(ViewGroup.java:3378)    at android.view.ViewGroup.addView(ViewGroup.java:3249)   at android.support.v4.view.ViewPager.addView(ViewPager.java:1413)  at android.view.ViewGroup.addView(ViewGroup.java:3194)  at com.xiaoyan.xiejinxiong.unlimitedslideviewpager.MyViewPagerAdapter.instantiateItem(MyViewPagerAdapter.java:29)  at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:943)  at android.support.v4.view.ViewPager.populate(ViewPager.java:1125)   at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)    at android.support.v4.view.ViewPager$3.run(ViewPager.java:254) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)  at android.view.Choreographer.doCallbacks(Choreographer.java:555)   at android.view.Choreographer.doFrame(Choreographer.java:524)  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)  at android.os.Handler.handleCallback(Handler.java:615)  at android.os.Handler.dispatchMessage(Handler.java:92)   at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745)  at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511)   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)  at dalvik.system.NativeStart.main(Native Method)
报错代码:

        container.addView(mListViews.get(position% mListViews.size()), 0);//添加页卡
大概意思就是说mListViews.get(position% mListViews.size())所获得的View已经有parent,但是,现在你现在又将该View添加到parent中,这样是不行的,需要在parent添加该View之前将其remove掉。

也就是说,我们需要在 container.addView(mListViews.get(position% mListViews.size()), 0);之前,先使用container remove掉之前的mListViews.get(position% mListViews.size())的View。

需要实例化页卡代码改为:

    @Override    public Object instantiateItem(ViewGroup container, int position) {    //实例化页卡        container.removeView(mListViews.get(position % mListViews.size()));        container.addView(mListViews.get(position% mListViews.size()), 0);//添加页卡        return mListViews.get(position% mListViews.size());    }
运行:

在这时,你可以一直向左划,是可以不断地滑动的,但是,假如你是向右划的话,虽然不会报错,但是会出现一件很奇怪的事情,图片消失了,背景变得空白,后来,我输出       Log.v("NUM","container.getChildCount():"+container.getChildCount());

发现,在往左划的时候,并不会加载之前View,而是一直删除,因此,假如我们需要保证一定可以显示mListViews里面的全部View,那么,我们需要保证container.getChildCount()==mListViews.size()的时候,才开始删除mListViews.get(position % mListViews.size(),于是,需要实例化页卡代码改为:

    @Override    public Object instantiateItem(ViewGroup container, int position) {    //实例化页卡        if (container.getChildCount() == mListViews.size()) {            container.removeView(mListViews.get(position                    % mListViews.size()));        }        container.addView(mListViews.get(position% mListViews.size()), 0);//添加页卡        return mListViews.get(position% mListViews.size());    }

但是,这样居然会报错:

 java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.    at android.view.ViewGroup.addViewInner(ViewGroup.java:3378)    at android.view.ViewGroup.addView(ViewGroup.java:3249)   at android.support.v4.view.ViewPager.addView(ViewPager.java:1413)  at android.view.ViewGroup.addView(ViewGroup.java:3194)  at com.xiaoyan.xiejinxiong.unlimitedslideviewpager.MyViewPagerAdapter.instantiateItem(MyViewPagerAdapter.java:29)  at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:943)  at android.support.v4.view.ViewPager.populate(ViewPager.java:1125)   at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)    at android.support.v4.view.ViewPager$3.run(ViewPager.java:254) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)  at android.view.Choreographer.doCallbacks(Choreographer.java:555)   at android.view.Choreographer.doFrame(Choreographer.java:524)  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)  at android.os.Handler.handleCallback(Handler.java:615)  at android.os.Handler.dispatchMessage(Handler.java:92)   at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745)  at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511)   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)  at dalvik.system.NativeStart.main(Native Method)
后来,我百度谷歌了一下,发现把destroyItem方法修改一下即可:

    @Override    public void destroyItem(ViewGroup container, int position, Object object) {//删除页卡        container.removeView(container);//删除页卡    }
于是,该ViewPager可以一直向左滑动,往右滑动也不会出现错误。

但是,还是出现一个小问题,那就是第一页不能往右划。

这样问题,只需要在主页面修改默认显示页数即可,将其改为:

 viewPager.setCurrentItem(525);
这里的525可以随意修改,只要是 mListViews.size()的倍数,并且足够大就行,因为假如设置为525,向右滑动525次便可以滑到尽头,(- -但是一般没人这么无聊吧)


源码:http://download.csdn.net/detail/u011596810/9540534






1 0