ViewPager 实现无限轮播的小demo 以及对instantiateItem和destroyItem的一点理解

本文参考了https://www.jianshu.com/p/1ed6b41891ef

首先是布局文件
activity_main.xml:




    

        

            

            
        

        
    

这就是个普通的布局文件,ViewPager放在FrameLayout中,LinearLayout放在FrameLayout的底部。

在values文件夹中创建了paper_image_id.xml文件,以便后面给ViewPager的每个页面设置id,这样才能设置点击事件。



    
    
    
    

接下来是MainActivity.java

public class MainActivity extends AppCompatActivity {
    public static int curposition=0;//记录当前位置
    public ViewPager mViewPager;
    public TextView tv;
    public List mImageList;//轮播的图片集合
    public String[] mImageTitles;//标题集合
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    //初始化控件
    public void init(){
        mViewPager=findViewById(R.id.viewpager);
        tv=findViewById(R.id.tv_pager_title);
        initData();//初始化数据
        initView();//初始化View,设置适配器
    }

    //初始化数据(图片、标题、点击事件)
    public void initData(){
        mImageList=new ArrayList<>();
        mImageTitles=new String[]{"title4","title1","title2","title3","title4","title1"};
        int ImageRes[]=new int[]{R.drawable.apple_pic,R.drawable.banana_pic,R.drawable.cherry_pic,R.drawable.grape_pic};
        //加入最后一张图片,以形成无限循环
        ImageView iv;
        iv=new ImageView(this);
        iv.setBackgroundResource(ImageRes[3]);
        iv.setId(R.id.pager_image1);
        iv.setOnClickListener(new PagerImageOnClick());
        mImageList.add(iv);
        for(int i=0;i<4;i++){
            iv=new ImageView(this);
            iv.setBackgroundResource(ImageRes[i]);
            iv.setId(R.id.pager_image1);
            iv.setOnClickListener(new PagerImageOnClick());
            mImageList.add(iv);
        }
        iv=new ImageView(this);
        iv.setBackgroundResource(ImageRes[0]);
        iv.setId(R.id.pager_image1);
        iv.setOnClickListener(new PagerImageOnClick());
        mImageList.add(iv);
    }

    //给ViewPager设置适配器
    public void initView(){
        MyViewPagerAdapter viewPagerAdapter=new MyViewPagerAdapter(mImageList,mViewPager);
        mViewPager.setAdapter(viewPagerAdapter);
        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }
            //每次切换页面都会调用这个方法
            //不论是用户手动切换或者是代码导致的切换(setCurrentItem)
            @Override
            public void onPageSelected(int position) {
                //这里的position是当前page对应的下标
                curposition=position;
                tv.setText(mImageTitles[position]);

            }
            @Override
            public void onPageScrollStateChanged(int state) {
                //验证当前的滑动是否结束
                if(state==ViewPager.SCROLL_STATE_IDLE){
                    if(curposition==0){
                        mViewPager.setCurrentItem(4,false);//false表示不要动画效果
                    }else if(curposition==5){
                        mViewPager.setCurrentItem(1,false);
                    }
                }
            }
        });
        mViewPager.setCurrentItem(1);
    }




    private class PagerImageOnClick implements View.OnClickListener{
        @Override
        public void onClick(View v){
            switch (v.getId()){
                case R.id.pager_image1:
                    Toast.makeText(MainActivity.this,"图片1被点击",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.pager_image2:
                    Toast.makeText(MainActivity.this,"图片2被点击",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.pager_image3:
                    Toast.makeText(MainActivity.this,"图片3被点击",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.pager_image4:
                    Toast.makeText(MainActivity.this,"图片4被点击",Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

    
    class MyViewPagerAdapter extends PagerAdapter{
        private List imageViewList;
        private ViewPager viewPager;

        public MyViewPagerAdapter(List imageViewList,ViewPager viewPager){
            this.viewPager=viewPager;
            this.imageViewList=imageViewList;
        }
        @Override
        //获取要滑动的控件的数量
        //position的最大数目
        public int getCount(){
            return mImageList.size();
        }
        @Override
        public boolean isViewFromObject(View view, Object object){
            return view==object;
        }
        @Override
        //一个page在切换完成后会调用该方法去加载下一个可能将被展示的page
        //如page1切换到page2,则会调用该方法加载page3
        //而从page3切换到page1,则会调用该方法加载page1
        public Object instantiateItem(ViewGroup container,int position){

            container.addView(mImageList.get(position));
            return mImageList.get(position);
        }

        //ViewPager只会保留当前页和当前页左右两页
        //如从page2滑到page3,则page1会被删除
        @Override
        public void destroyItem(ViewGroup container,int position,Object object){
            viewPager.removeView(imageViewList.get(position));
        }
    }
}

这里需要一步一步看代码。
首先onCreate()调用了init()进行初始化。init()中又调用了initData()和initView()做具体的初始化操作。
在initData()中:

public void initData(){
        mImageList=new ArrayList<>();
        mImageTitles=new String[]{"title4","title1","title2","title3","title4","title1"};
        int ImageRes[]=new int[]{R.drawable.apple_pic,R.drawable.banana_pic,R.drawable.cherry_pic,R.drawable.grape_pic};
        //加入最后一张图片,以形成无限循环
        ImageView iv;
        iv=new ImageView(this);
        iv.setBackgroundResource(ImageRes[3]);
        iv.setId(R.id.pager_image1);
        iv.setOnClickListener(new PagerImageOnClick());
        mImageList.add(iv);
        for(int i=0;i<4;i++){
            iv=new ImageView(this);
            iv.setBackgroundResource(ImageRes[i]);
            iv.setId(R.id.pager_image1);
            iv.setOnClickListener(new PagerImageOnClick());
            mImageList.add(iv);
        }
        iv=new ImageView(this);
        iv.setBackgroundResource(ImageRes[0]);
        iv.setId(R.id.pager_image1);
        iv.setOnClickListener(new PagerImageOnClick());
        mImageList.add(iv);
    }

这里的关键之处在于,原本我们想展示4张图片,并实现他们的循环播放,这里我们在图1之前加入了图4,在图4之后加入了图1。也就是说,原本我们只想展示4张图,这里的mImageList实际上却有6个ImageView。这样做的目的是,当我们从图4左滑时,我们能看到图1的部分(实际上它位于mImageList的下标5的位置),然后当我们滑动完成,下标5处的图1展示出来时,立刻切换到下标1的图1处,这样就实现了无限轮播的目的。

接下来分析initView()的代码:

//给ViewPager设置适配器
    public void initView(){
        MyViewPagerAdapter viewPagerAdapter=new MyViewPagerAdapter(mImageList,mViewPager);
        mViewPager.setAdapter(viewPagerAdapter);
        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }
            //每次切换页面都会调用这个方法
            //不论是用户手动切换或者是代码导致的切换(setCurrentItem)
            @Override
            public void onPageSelected(int position) {
                //这里的position是当前page对应的下标
                curposition=position;
                tv.setText(mImageTitles[position]);
            }
            @Override
            public void onPageScrollStateChanged(int state) {
                //验证当前的滑动是否结束
                if(state==ViewPager.SCROLL_STATE_IDLE){
                    if(curposition==0){
                        mViewPager.setCurrentItem(4,false);//false表示不要动画效果
                    }else if(curposition==5){
                        mViewPager.setCurrentItem(1,false);
                    }
                }
            }
        });
        mViewPager.setCurrentItem(1);
    }

分析initView()的代码之前先看看自定义的ViewPager适配器的代码

class MyViewPagerAdapter extends PagerAdapter{
        private List imageViewList;
        private ViewPager viewPager;

        public MyViewPagerAdapter(List imageViewList,ViewPager viewPager){
            this.viewPager=viewPager;
            this.imageViewList=imageViewList;
        }
        @Override
        //获取要滑动的控件的数量
        //position的最大数目
        public int getCount(){
            return mImageList.size();
        }
        @Override
        public boolean isViewFromObject(View view, Object object){
            return view==object;
        }
        @Override
        //一个page在切换完成后会调用该方法去加载下一个可能将被展示的page
        //如page1切换到page2,则会调用该方法加载page3
        //而从page3切换到page2,则会调用该方法加载page1
        public Object instantiateItem(ViewGroup container,int position){

            container.addView(mImageList.get(position));
            return mImageList.get(position);
        }

        //ViewPager只会保留当前页和当前页左右两页
        //如从page2滑到page3,则page1会被删除
        @Override
        public void destroyItem(ViewGroup container,int position,Object object){
            viewPager.removeView(imageViewList.get(position));
        }
    }

这就是个简单的ViewPager适配器。
instantiateItem()方法在一个page切换完成时会被调用,加载下一个可能被展示的page。如我从page1切换到page2,那么instantiateItem()方法会加载page3;而从page3切换到page2,则会加载page1;
destroyItem()方法的调用,ViewPager值会保留当前页和当前页的左右两页。如果从page2切换到page3,则page1会被删除,因为page3的左右时page2和page4.

看完了适配器后再看看initView().
initView()主要的工作就是为viewPager设置一个适配器。设置完适配器之后又给ViewPager设置了翻页的响应事件。
这里重写了onPageSelected()和onPageScrollStateChanged()
每次页面的切换完成,onPageSelected()方法就会被调用。不论是用户滑动页面导致的页面切换还是代码setCutrrentItem()导致的页面切换,都会调用这个方法。这里我们获取了当前页面的下标。

**而onPageScrollStateChanged()在滑动状态发生改变时会被调用。例如:从静止到突然有滑动发生时,会调用;从滑动状态突然停下来(未切换页面)也会调用;从滑动状态到滑动完成(成功切换页面)也会调用。在这里当滑动结束时,如果当前下标是5,即从图4滑动到下标5的图1时,就应该切换到下标1的图1且不应该有切换的动画效果。**下标为0时同理切换到下标4的图4

你可能感兴趣的:(ViewPager 实现无限轮播的小demo 以及对instantiateItem和destroyItem的一点理解)