viewpager_viewpagerindicator - CSDN
精华内容
参与话题
  • ViewPager 详解(一)---基本入门

    万次阅读 多人点赞 2019-09-11 15:37:53
    前言:这两天研究研究ViewPager滚动功能,现在很多的app都有用到这个功能,我们的大虾米也有这个模块。要研究就彻底的研究研究,我从不满足于一个功能只是简单的应用,要学就学的彻底,所以我打算将ViewPager 分几篇...

    前言:这两天研究研究ViewPager滚动功能,现在很多的app都有用到这个功能,我们的大虾米也有这个模块。要研究就彻底的研究研究,我从不满足于一个功能只是简单的应用,要学就学的彻底,所以我打算将ViewPager 分几篇写,研究的哪个程度就写到哪个程度吧。今天是第一篇,基本入门篇 。

     

     

    相关文章:

    1、《ViewPager 详解(一)---基本入门》

    2、《ViewPager 详解(二)---详解四大函数》

    3、《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》

    4、《ViewPager 详解(四)----自主实现滑动指示条》

    5、《ViewPager 详解(五)-----使用Fragment实现ViewPager滑动》

     

    首先让大家有个全局的认识,直接上个项目,看看仅仅通过这几行代码,竟然就能完成如此强悍的功能。下篇再结合API仔细讲讲为什么要这么写。

    效果图:

    实现了三个view间的相互滑动

                         第一个VIEW向第二个VIEW滑动       第二个VIEW向第三个VIEW滑动

       

    一、新建项目,引入ViewPager控件

    ViewPager。它是google SDk中自带的一个附加包的一个类,可以用来实现屏幕间的切换。

    1.在主布局文件里加入

     

     

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        tools:context="com.example.testviewpage_1.MainActivity" >
    
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />
    
    </RelativeLayout>

     

    其中 <android.support.v4.view.ViewPager /> 是ViewPager对应的组件,要将其放到想要滑动的位置

    2、新建三个layout,用于滑动切换的视图

    从效果图中也可以看到,我们的三个视图都非常简单,里面没有任何的控件,大家当然可以往里添加各种控件,但这里是个DEMO,只详解原理即可,所以我这里仅仅用背景来区别不用layout布局。

    布局代码分别如下:

    layout1.xml

     

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:orientation="vertical" >
        
    
    </LinearLayout>

    layout2.xml

     

     

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffff00"
        android:orientation="vertical" >
        
    
    </LinearLayout>
    

    layout3.xml

     

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ff00ff"
        android:orientation="vertical" >
        
    
    </LinearLayout>
    
    

     

    二、代码实战

    先上整体代码,然后逐步讲解。

    package com.example.testviewpage_1;
    /**
     * @author  harvic
     * @date 2014.8.9
     */
    import java.util.ArrayList;
    import java.util.List;
    import java.util.zip.Inflater;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    
    public class MainActivity extends Activity {
    
    	private View view1, view2, view3;
    	private ViewPager viewPager;  //对应的viewPager
    	
    	private List<View> viewList;//view数组
       
       
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            viewPager = (ViewPager) findViewById(R.id.viewpager);
            LayoutInflater inflater=getLayoutInflater();
            view1 = inflater.inflate(R.layout.layout1, null);
            view2 = inflater.inflate(R.layout.layout2,null);
            view3 = inflater.inflate(R.layout.layout3, null);
            
            viewList = new ArrayList<View>();// 将要分页显示的View装入数组中
    		viewList.add(view1);
    		viewList.add(view2);
    		viewList.add(view3);
    		
    		
    		PagerAdapter pagerAdapter = new PagerAdapter() {
    			
    			@Override
    			public boolean isViewFromObject(View arg0, Object arg1) {
    				// TODO Auto-generated method stub
    				return arg0 == arg1;
    			}
    			
    			@Override
    			public int getCount() {
    				// TODO Auto-generated method stub
    				return viewList.size();
    			}
    			
    			@Override
    			public void destroyItem(ViewGroup container, int position,
    					Object object) {
    				// TODO Auto-generated method stub
    				container.removeView(viewList.get(position));
    			}
    			
    			@Override
    			public Object instantiateItem(ViewGroup container, int position) {
    				// TODO Auto-generated method stub
    				container.addView(viewList.get(position));
    				
    				
    				return viewList.get(position);
    			}
    		};
    		
    		
    		viewPager.setAdapter(pagerAdapter);
    		
        }
    
    
    }

    代码量很小,全部放在了OnCreate()函数中。

     

    1、先看声明的变量的意义:

     

     

    private View view1, view2, view3;
    private List<View> viewList;//view数组
    private ViewPager viewPager;  //对应的viewPager

     

    首先viewPager对应 <android.support.v4.view.ViewPager/>控件。

    view1,view2 ,view3对应我们的三个layout,即layout1.xml,layout2.xml,layout3.xml

    viewList是一个View数组,盛装上面的三个VIEW

    2、接下来是他们的初始化过程:

     

    viewPager = (ViewPager) findViewById(R.id.viewpager);
    LayoutInflater inflater=getLayoutInflater();
    view1 = inflater.inflate(R.layout.layout1, null);
    view2 = inflater.inflate(R.layout.layout2,null);
    view3 = inflater.inflate(R.layout.layout3, null);
    
    viewList = new ArrayList<View>();// 将要分页显示的View装入数组中
    viewList.add(view1);
    viewList.add(view2);
    viewList.add(view3);

    初始化过程难度不大,就是将资源与变量联系起来布局,最后将实例化的view1,view2,view3添加到viewList中

     

    3、PageAdapter——PageView的适配器

     

    适配器这个东东想必大家都不莫生,在ListView中也有适配器,listView通过重写GetView()函数来获取当前要加载的Item。而PageAdapter不太相同,毕竟PageAdapter是单个VIew的合集。

    PageAdapter 必须重写的四个函数:

     

    • boolean isViewFromObject(View arg0, Object arg1)
    • int getCount() 
    • void destroyItem(ViewGroup container, int position,Object object)
    • Object instantiateItem(ViewGroup container, int position)

     

    先看看各个函数,我们上面都做了什么吧:

     

    @Override
    public int getCount() {
    	// TODO Auto-generated method stub
    	return viewList.size();
    }

    getCount():返回要滑动的VIew的个数

     

     

    @Override
    public void destroyItem(ViewGroup container, int position,
    		Object object) {
    	// TODO Auto-generated method stub
    	container.removeView(viewList.get(position));
    }
    

    destroyItem():从当前container中删除指定位置(position)的View;

     

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
    	// TODO Auto-generated method stub
    		container.addView(viewList.get(position));
    		
    		
    		return viewList.get(position);
    	}
    };

    instantiateItem():做了两件事,第一:将当前视图添加到container中,第二:返回当前View

     

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
    	// TODO Auto-generated method stub
    	return arg0 == arg1;
    }

    isViewFromObject():对于这个函数就先不做讲解,大家目前先知道它要这样重写就行了,后面我们会对它进行改写。

     

    下一篇,我将仔细讲解这几个函数的意义,与有关Key的知识,当然最后也会有个例子给大家。这篇就到这了。

     

    源码地址:http://download.csdn.net/detail/harvic880925/7733249

     

    请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/38453725  万分感激!!!!!

    如果你喜欢我的文章,你可能更喜欢我的公众号

    启舰杂谈

     

    展开全文
  • ViewPager使用详解

    2017-12-22 23:33:52
    ViewPager使用详解这两天看了鸿洋大神的一篇关于ViewPager的推送,将其中的内容实现了下,过程中依旧踩坑不断,现在将填坑过程中的一些解决方法及理解记录一下。ViewPager+PageAdapter这是最基本的一种使用,要注意...

    这两天看了鸿洋大神的一篇关于ViewPager的推送,将其中的内容实现了下,过程中依旧踩坑不断,现在将填坑过程中的一些解决方法及理解记录一下。

    ViewPager+PageAdapter

    这是最基本的一种使用,要注意的是,PagaAdapter中有4个必须要重写的方法:
    - getCount()
    需要在viewpager中显示的对象数。
    - isViewFromObject(View view, Object object)
    直接return view==object;
    - instantiateItem(ViewGroup container, int position)
    要显示页面的初始化,其中return 语句中返回的object才是显示的内容。
    - destroyItem(ViewGroup container, int position, Object object)
    页面不是当前显示页面,也不是缓存页面,则回调该方法将其销毁。

    ViewPager+FragmentPagerAdapter+TabLayout

    这里写图片描述
    用FragmentPagerAdapter的话,通常重写两个方法:

    @Override
               public Fragment getItem(int position) {
                   return list.get(position);
               }
    
               @Override
               public int getCount() {
                   return list.size();
               }

    这里要注意的是,在new一个FragmentPagerAdapter时,需要传入一个FragmentManager,而这个FragmentManager是v4包中的,它的获取方式是

    fragmentManager=getSupportFragmentManager();

    而不是常用的 fragmentManager1=getFragmentManager();
    我们用fragment时因为它能实现更多的逻辑,降低耦合性,而用view的话,也可以进行某些实现,但是代码就会全部冗杂在一块儿,后面如果修改就会很麻烦。
    我们可以结合TabLayout实现页面滑动时上层标签的内容改变。
    1.重写adapter中的getPageTitle()方法,它的返回值即标签中的内容

    @Override
                public CharSequence getPageTitle(int position) {
                    switch (position){
                        case 0:return "first";
                        case 1:return "second";
                        case 2:return "third";
                        default:return "hello";
                    }
               }

    这里case后不需要break了,因为用了return离开了该方法,也不需要用switch语句后用return,因为有default语句,不管是否有符合的值,都会return。
    2.将ViewPager与TabLayout“绑定”

    tabLayout.setupWithViewPager(viewPager);

    当两者绑定后,其实是TabLayout通过ViewPager调用它的getPageTitle()方法来实现联动。
    这里有一个知识点,就是FragmentPagerAdapter与FragmentStatePagerAdapter的区别,鸿洋大神写得很清楚了,这里就直接引用了。

    FragmentPagerAdapter:对于不再需要的 fragment,选择调用 onDetach() 方法,仅销毁视图,并不会销毁 fragment 实例。
    FragmentStatePagerAdapter:会销毁不再需要的 fragment,当当前事务提交以后,会彻底的将 fragmeng 从当前 Activity 的FragmentManager 中移除,state 标明,销毁时,会将其 onSaveInstanceState(Bundle outState) 中的 bundle 信息保存下来,当用户切换回来,可以通过该 bundle 恢复生成新的 fragment,也就是说,你可以在 onSaveInstanceState(Bundle outState) 方法中保存一些数据,在 onCreate 中进行恢复创建。

    总结起来就是:当页面多的时候,就用FragmentStatePagerAdapter来省内存;页面少时,就用FragmentPagerAdapter来提升效率。

    ViewPager的轮播

    1.自动无限轮播
    即在一定时间间隔时更换页面,这里通过handler就可以实现了。

     Handler handler=new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what==0011){
                        viewPager.setCurrentItem((viewPager.getCurrentItem()+1)%list.size());
                        this.sendEmptyMessageDelayed(0011,1000);
                    }
                }
            };
            handler.sendEmptyMessageDelayed(0011,1000);

    2.手动实现轮播
    所谓的手动实现轮播,就是在最后一个页面往后滑动时可以回到第一个页面。而这也是与banner很大的一个区别,banner是可以直接实现的,而viewpager我们则需要写一些内容。
    先上代码:

    @Override
                public int getCount() {
                    return Integer.MAX_VALUE;
                }
    
                @Override
                public Object instantiateItem(ViewGroup container, int position) {
    
                    View view=list.get(position%list.size());
                    ViewGroup viewGroup=(ViewGroup)view.getParent();
                    if (viewGroup!=null) viewGroup.removeView(view);
                    container.addView(view);
                    return view;
                }
    
                @Override
                public void destroyItem(ViewGroup container, int position, Object object) {}

    因为我们要实现“从尾到头”的变化,而这个变化也不知道要多少次,所以我们就通过getCount()给了一个绝对大的值来实现。
    重点在instantiateItem()中,如果我们按照之前的写法,即

    @Override
                public Object instantiateItem(ViewGroup container, int position) {
                    View view=list.get(position);
                    container.addView(view);
                    return  view;
                }
    
                @Override
                public void destroyItem(ViewGroup container, int position, Object object) {
                    container.removeView(list.get(position));
                }

    我们会发现当往回滑动的时候,程序会崩掉,这是因为图片第一次加载了,当往回滑动,它再一次加载时,我们需要在它的父类中先将该object删除了,再重新加载新的对象。
    这里还有一个要注意的是,因为我们在instantiateItem()中已经对图片的移除做了处理了,所以就不需要重写destroyItem()方法了。如果我们按照上面的代码重写了该方法,会发现显示的内容为空。

    ViewPager中滑动页面后文字改变

    我们可以选择在instantiateItem()中根据当前的position来获得文字内容,但这样滑动时会显得比较生硬,所以可以选择将textview与ViewPager分离开,通过对ViewPager添加监听,来达到页面变化时文字内容改变。

    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
    
                @Override
                public void onPageSelected(int position) {
                      textView.setText(titles[position%titles.length]);
                }
    
                @Override
                public void onPageScrollStateChanged(int state) {}
            });

    同屏显示多个页面

    这里的同屏显示多个页面,并不是ViewPager中显示多个,实际上它还是只显示了一个页面,但是我们通过它与其父布局及它与前后两个页面之间的margin来达到3个页面(部分页面)的同时出现。需要用到的几个方法:
    - clipChildren=”false”
    设定值为false后,才可以使得子view的裁剪不受影响
    - viewPager.setPageMargin( )
    设置每两个页面之间的margin
    - viewPager.setOffscreenPageLimit( )
    设置需要显示在屏幕上的页面的个数
    这里贴出xml的布局:

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false">
    
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpagers"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        android:layout_gravity="center"
        android:layout_marginLeft="60dp"
        android:layout_marginRight="60dp" />
    </LinearLayout>

    当我们实现多屏显示后,如果觉得单调,想让页面随着滑动的位置不同,改变图片的透明度,可以调用viewPager.setPageTransformer( )来增加特效。

    viewPager.setPageTransformer(false, new ViewPager.PageTransformer() {
                private static final float DEFAULT_MIN_ALPHA = 0.5f;
                private float mMinAlpha = DEFAULT_MIN_ALPHA;
                @Override
                public void transformPage(View page, float position) {
                    if (position < -1)
                    {
                        page.setAlpha(mMinAlpha);
                    } else if (position <= 1)
                    { // [-1,1]
    
                        if (position < 0) //[0,-1]
                        {
                            float factor = mMinAlpha + (1 - mMinAlpha) * (1 + position);
                            page.setAlpha(factor);
                        } else//[1,0]
                        {
                            float factor = mMinAlpha + (1 - mMinAlpha) * (1 - position);
                            page.setAlpha(factor);
                        }
                    } else
                    { // (1,+Infinity]
                        page.setAlpha(mMinAlpha);
                    }
                }
            });

    关于这个动画,还可以看下大神的另一篇文章
    巧用ViewPager 打造不一样的广告轮播切换效果

    展开全文
  • Android之ViewPager,Fragment知识全讲

    万人学习 2019-11-15 15:32:32
    本课程讲解Android中的ViewPager,Fragment及Android触摸事件的处理,ViewPager和Fragment相互嵌套冲突处理
  • ViewPager+Fragment+选项卡

    千次阅读 2019-05-22 22:01:50
    ViewPager 这是在手机上最常见的一种控件,几乎每款手机软件都会应用,ViewPager+Fragment的使用可以实现更加美观的界面和效果。 java代码: 主类: package com.example.day13; import android.support.design....

    ViewPager

    这是在手机上最常见的一种控件,几乎每款手机软件都会应用,ViewPager+Fragment的使用可以实现更加美观的界面和效果。

    在这里插入图片描述
    在这里插入图片描述

    java代码:

    主类:

    package com.example.day13;
    
    import android.support.design.widget.TabLayout;
    import android.support.v4.app.Fragment;
    import android.support.v4.view.ViewPager;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.CompoundButton;
    import android.widget.RadioButton;
    
    import java.util.ArrayList;
    
    public class day13 extends AppCompatActivity {
        ViewPager vp;
        RadioButton first;
        RadioButton second;
        TabLayout tl;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_day13);
    
            vp = findViewById(R.id.vp);
            first = findViewById(R.id.first);
            second = findViewById(R.id.second);
            tl = findViewById(R.id.tb);
    
            first.setChecked(true);
            ArrayList<Fragment> list = new ArrayList<>();
            ArrayList<String> titles = new ArrayList<>();
            One one = new One();
            Two two = new Two();
    
            list.add(one);
            list.add(two);
            titles.add("选项卡1");
            titles.add("选项卡2");
            vp.setAdapter(new MyAdapter(getSupportFragmentManager(),list,titles));
            tl.setupWithViewPager(vp);
    
            first.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (isChecked){
                        vp.setCurrentItem(0);
                    }
                }
            });
    
            second.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if(isChecked){
                        vp.setCurrentItem(1);
                    }
                }
            });
    
            vp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int i, float v, int i1) {
    
                }
    
                @Override
                public void onPageSelected(int i) {
                    switch(i){
                        case 0:
                            first.setChecked(true);
                            break;
                        case 1:
                            second = findViewById(R.id.second);
                            second.setChecked(true);
                            break;
                    }
                }
    
                @Override
                public void onPageScrollStateChanged(int i) {
    
                }
            });
    
        }
    }
    

    适配器代码:

    package com.example.day13;
    
    
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentPagerAdapter;
    
    import java.util.ArrayList;
    
    public class MyAdapter extends FragmentPagerAdapter {
    
        ArrayList<Fragment> fragments;
        ArrayList<String> titles;
        public MyAdapter(FragmentManager fm, ArrayList<Fragment> fragments,ArrayList<String> titles) {
            super(fm);
            this.fragments = fragments;
            this.titles = titles;
        }
    
        @Override
        public Fragment getItem(int i) {
            return fragments.get(i);
        }
    
        @Override
        public int getCount() {
            return fragments.size();
        }
    
        @Nullable
        @Override
        public CharSequence getPageTitle(int position) {
            return titles.get(position);
        }
    }
    
    

    Fragment类代码:

    package com.example.day13;
    
    import android.os.Bundle;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class One extends Fragment {
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            return inflater.inflate(R.layout.layout_one,container,false);
        }
    }
    
    

    效果图:
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • ViewPager详解

    千次阅读 2016-02-22 01:03:50
    ViewPager详解

    ViewPager详解

    • ViewPager中的主要方法详解
    • OnPageChangeListener中的三个方法详解
    • 三种适配器的使用及其主要方法详解

    ViewPager用于实现页面间的切换。

    ViewPager中的主要方法详解

    • setAdapter(PagerAdapter adapter)
      该方法为ViewPager设置适配器,ViewPager有三种适配器,它们分别有不同的特性,下面我会对这三种适配器进行讲解。
    • setCurrentItem(int item)
      该方法设置显示item位置的界面。
    • setOffscreenPageLimit(int limit)
      该方法用来设置当前显示页面左右两边缓存的页面数。
    • addOnPageChangeListener(OnPageChangeListener listener)
      该方法为ViewPager添加页面切换时的监听,关于界面监听的内容,接下来对OnPageChangeListener中的方法进行讲解时,再详细说明。
    • setOnScrollChangeListener(OnScrollChangeListener l)
      该方法为ViewPager增加滚动状态监听,但该方法需要minSdkVersion为23

    OnPageChangeListener中的三个方法详解

    • onPageScrollStateChanged(int state)
      该方法在手指操作屏幕的时候发生变化。有三个值:0(END),1(PRESS) ,2(UP) 。当用手指滑动翻页时,手指按下去的时候会触发这个方法,state值为1,手指抬起时,如果发生了滑动(即使很小),这个值会变为2,然后最后变为0 。总共执行这个方法三次。一种特殊情况是手指按下去以后一点滑动也没有发生,这个时候只会调用这个方法两次,state值分别是1,0 。当setCurrentItem翻页时,会执行这个方法两次,state值分别为2 ,0 。
    • onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
      该方法在滑动过程中将一直被调用,该方法的参数说明如下:
      position:当用手指滑动时,如果手指按在页面上不动,position和当前页面index是一致的;如果手指向左拖动(相应页面向右翻动),这时候position大部分时间和当前页面是一致的,只有翻页成功的情况下最后一次调用才会变为目标页面;如果手指向右拖动(相应页面向左翻动),这时候position大部分时间和目标页面是一致的,只有翻页不成功的情况下最后一次调用才会变为原页面。当直接设置setCurrentItem翻页时,如果是相邻的情况(比如现在是第二个页面,跳到第一或者第三个页面),如果页面向右翻动,大部分时间是和当前页面是一致的,只有最后才变成目标页面;如果向左翻动,position和目标页面是一致的。这和用手指拖动页面翻动是基本一致的。如果不是相邻的情况,比如我从第一个页面跳到第三个页面,position先是0,然后逐步变成1,然后逐步变成2;我从第三个页面跳到第一个页面,position先是1,然后逐步变成0,并没有出现为2的情况。
      positionOffset:当前页面滑动比例,如果页面向右翻动,这个值不断变大,最后在趋近1的情况后突变为0。如果页面向左翻动,这个值不断变小,最后变为0。
      positionOffsetPixels:当前页面滑动像素,变化情况和positionOffset一致
    • onPageSelected(int position)
      position是被选中页面的索引,该方法在页面被选中或页面滑动足够距离切换到该页手指抬起时调用。

    三个方法的执行顺序:用手指拖动翻页时,最先执行一遍onPageScrollStateChanged(1),然后不断执行onPageScrolled,放手指的时候,直接立即执行一次onPageScrollStateChanged(2),然后立即执行一次onPageSelected,然后再不断执行onPageScrollStateChanged,最后执行一次onPageScrollStateChanged(0)

    三种适配器的使用及其主要方法详解

    三种适配器继承关系

    这里写图片描述

    PagerAdapter
    主要方法详解
    • public abstract int getCount ()
      返回有效视图的数量。
    • public int getItemPosition (Object object)
      当宿主视图尝试判断一项的位置是否改变时调用。如果给定项的位置没有改变则返回POSITION_UNCHANGED,如果该项不再存在于适配器中则返回POSITION_NONE
      在ViewPager.dataSetChanged()中将对该函数的返回值进行判断,如果返回POSITION_NONE则调用destroyItem(ViewGroup container, int position, Object object)方法将该视图销毁,如果返回POSITION_UNCHANGED则不做任何改变,如果数据改变,则触发PagerAdapter.instantiateItem(ViewGroup container, int position)方法改变视图。
      PagerAdapter中该方法的默认返回值是 POSITION_UNCHANGED。如果没有重载该函数,而导致调用PagerAdapter.notifyDataSetChanged() 后,什么都没有发生。
    • public boolean isViewFromObject (View view, Object object)
      决定一个页面view是否与instantiateItem(ViewGroup, int)方法返回的具体key对象相关联。
      viewpager不直接处理每一个视图而是将各个视图与一个键联系起来。这个键用来跟踪且唯一代表一个页面,不仅如此,该键还独立于这个页面所在adapter的位置。当pageradapter将要改变的时候他会调用startUpdate函数,接下来会调用一次或多次的instantiateItem或者destroyItem。最后在更新的后期会调用finishUpdate。当finishUpdate返回时instantiateItem返回的对象应该添加到父ViewGroup,destroyItem返回的对象应该被ViewGroup删除。isViewFromObject(View, Object)代表了当前的页面是否与给定的键相关联。
      自定义Key示例-简单的将位置position最为key
    private class MyPagerAdapter extends PagerAdapter {
    
            private List<View> mViewList;
    
            MyPagerAdapter(List<View> viewList) {
                mViewList = viewList;
            }
    
            @Override
            public int getCount() {
                Log.i(TAG, NAME + "--getCount");
                return mViewList.size();
            }
    
            @Override
            public int getItemPosition(Object object) { 
                return super.getItemPosition(object);
            }
    
            @Override
            public boolean isViewFromObject(View view, Object object) {
                Log.i(TAG, NAME + "--isViewFromObject");
                return view == mViewList.get((int)Integer.parseInt(object.toString()));
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                View view = mViewList.get(position);
                container.addView(view);
                Log.i(TAG, NAME + "--instantiateItem++container:" + container.getChildCount() + "++position:" + position);
                return position;
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(mViewList.get(position));
                Log.i(TAG, NAME + "--destroyItem++container:" + container.getChildCount() + "++position:" + position);
            }
    
        }
    • public Object instantiateItem (ViewGroup container, int position)
      创建指定位置的页面视图。适配器有责任增加即将创建的View视图到给定的container中,确保在finishUpdate(viewGroup)返回时,增加视图的事情已经完成。
      该方法的返回值是新增视图页面的Object(Key),这里没必要非要返回视图本身,也可以是这个页面的其它容器,它可以返回和视图相关联的任何值。
    • public void destroyItem (ViewGroup container, int position, Object object)
      移除给定位置的view,适配器有责任将该view从container中移除,确保在finishUpdate(viewGroup)返回时,移除视图的事情已经完成。
    • public void startUpdate (ViewGroup container)
      在展示的界面中有改变将要发生时调用。
    • public void finishUpdate (ViewGroup container)
      展示界面中的改变完成时调用。在这个时间点上,你必须确保所有的页面已被合适的从container中添加或移除。
    • public void notifyDataSetChanged ()
      该方法由应用程序在适配器数据改变时主动调用。
    • public void registerDataSetObserver (DataSetObserver observer)
      注册一个观察者去接收关联到适配器数据变化的回调。
    • public void unregisterDataSetObserver (DataSetObserver observer)
      反注册去接收关联到适配器数据变化的回调的观察者。
    • public void setPrimaryItem (ViewGroup container, int position, Object object)
      调用该方法去通知当前适配器的哪一项被考虑为“primary”,它是当前展示给用户的页面。
    • public CharSequence getPageTitle (int position)
      该方法由ViewPager在获取描述页面的标题时调用。该方法默认返回null。
    • public float getPageWidth (int position)
      该方法返回给定页面的比例宽度,范围(0.f-1.f]。
    • public Parcelable saveState ()
      保存与适配器关联的实例状态,当当前UI状态需要重建时恢复。
    • public void restoreState (Parcelable state, ClassLoader loader)
      恢复之前由saveState ()保存的与适配器关联的实例状态。
    PagerAdapter使用示例

    activity_pager_adapter.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.example.sunxiaodong.viewpager.PagerAdapterActivity">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
        </android.support.v4.view.ViewPager>
    
        <TextView
            android:id="@+id/page_num"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:textColor="#ffffff"
            android:textSize="20sp" />
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true">
    
            <EditText
                android:id="@+id/edit_text"
                android:layout_width="100dp"
                android:layout_height="50dp"
                android:layout_gravity="center_vertical"
                android:textColor="#000000"
                android:textSize="20sp" />
    
            <Button
                android:id="@+id/button"
                android:layout_width="80dp"
                android:layout_height="40dp"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:text="跳转"
                android:textColor="#ffffff" />
        </LinearLayout>
    
    </RelativeLayout>

    page1.xml文件

    <?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"
        android:background="#ff0000">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="page1"
            android:textColor="#ffffff"
            android:textSize="20sp" />
    
    </RelativeLayout>

    page2.xml文件

    <?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"
        android:background="#ff00ff">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="page2"
            android:textColor="#ffffff"
            android:textSize="20sp" />
    
    </RelativeLayout>

    page3.xml文件

    <?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"
        android:background="#00ff00">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="page3"
            android:textColor="#ffffff"
            android:textSize="20sp" />
    
    </RelativeLayout>

    page4.xml文件

    <?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"
        android:background="#ffff00">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="page4"
            android:textColor="#ffffff"
            android:textSize="20sp" />
    
    </RelativeLayout>

    page5.xml文件

    <?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"
        android:background="#8e35ef">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="page5"
            android:textColor="#ffffff"
            android:textSize="20sp" />
    
    </RelativeLayout>

    PagerAdapterActivity.java文件

    public class PagerAdapterActivity extends AppCompatActivity implements View.OnClickListener {
    
        private static final String NAME = PagerAdapterActivity.class.getSimpleName();
        private static final String TAG = "sxd";
    
        private ViewPager mViewPager;
        private MyPagerAdapter mMyPagerAdapter;
        private TextView mPageNum;
        private EditText mEditText;
        private Button mButton;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_pager_adapter);
            initView();
        }
    
        private void initView() {
            mViewPager = (ViewPager) this.findViewById(R.id.viewpager);
            mPageNum = (TextView) this.findViewById(R.id.page_num);
            mEditText = (EditText) this.findViewById(R.id.edit_text);
            mButton = (Button) this.findViewById(R.id.button);
            mButton.setOnClickListener(this);
    
            List<View> viewList = new ArrayList<View>();
    
            LayoutInflater layoutInflater = getLayoutInflater();
            View view1 = layoutInflater.inflate(R.layout.page1, null);
            View view2 = layoutInflater.inflate(R.layout.page2, null);
            View view3 = layoutInflater.inflate(R.layout.page3, null);
            View view4 = layoutInflater.inflate(R.layout.page4, null);
            View view5 = layoutInflater.inflate(R.layout.page5, null);
    
            viewList.add(view1);
            viewList.add(view2);
            viewList.add(view3);
            viewList.add(view4);
            viewList.add(view5);
            mMyPagerAdapter = new MyPagerAdapter(viewList);
            mViewPager.setAdapter(mMyPagerAdapter);
            mViewPager.addOnPageChangeListener(new OnMyPageChangeListener());//页面变化监听
            mViewPager.setOffscreenPageLimit(2);//设置缓存页面数。当前页,左右两边(单边)最大缓存页面数。
    //        mViewPager.setOnScrollChangeListener(new OnMyScrollChangeListener());//滚动状态监听,minSdkVersion:23
    //        mViewPager.getCurrentItem();//获取当前显示页索引
    //        mViewPager.getOffscreenPageLimit();//获取缓存页面数
    //        mViewPager.onSaveInstanceState();
    //        mViewPager.setPageTransformer();
            mMyPagerAdapter.notifyDataSetChanged();
            setPageNum(0);//设置显示首页
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    goPage();
                    break;
            }
        }
    
        private void goPage() {
            String pageNumStr = mEditText.getText().toString();
            if (pageNumStr == null || pageNumStr.isEmpty()) {
                return;
            }
            int pageNum = Integer.parseInt(pageNumStr);
            if (pageNum > 0 && pageNum <= mMyPagerAdapter.getCount()) {
                mViewPager.setCurrentItem(pageNum - 1);//设置当前显示页索引
            }
        }
    
        private void setPageNum(int position) {
            String pageNum = (position + 1) + "/" + mMyPagerAdapter.getCount();
            mPageNum.setText(pageNum);
        }
    
        /*private class OnMyScrollChangeListener implements View.OnScrollChangeListener {
    
            @Override
            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
    
            }
        }*/
    
        /**
         * 页面变化监听器
         */
        private class OnMyPageChangeListener implements ViewPager.OnPageChangeListener {
    
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                Log.i(TAG, NAME + "--onPageScrolled++position:" + position + ",++positionOffset:" + positionOffset + ",++positionOffsetPixels:" + positionOffsetPixels);
            }
    
            @Override
            public void onPageSelected(int position) {
                Log.i(TAG, NAME + "--onPageSelected++position:" + position);
                setPageNum(position);
            }
    
            @Override
            public void onPageScrollStateChanged(int state) {
                Log.i(TAG, NAME + "--onPageScrollStateChanged++state:" + state);
            }
        }
    
        /**
         * 页面适配器
         */
        private class MyPagerAdapter extends PagerAdapter {
    
            private List<View> mViewList;
    
            MyPagerAdapter(List<View> viewList) {
                mViewList = viewList;
            }
    
            @Override
            public int getCount() {
                Log.i(TAG, NAME + "--getCount");
                return mViewList.size();
            }
    
            @Override
            public int getItemPosition(Object object) {
                Log.i(TAG, NAME + "--getItemPosition");
                return super.getItemPosition(object);
            }
    
            @Override
            public boolean isViewFromObject(View view, Object object) {
                Log.i(TAG, NAME + "--isViewFromObject");
                return view == object;
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                View view = mViewList.get(position);
                container.addView(view);
                Log.i(TAG, NAME + "--instantiateItem++container:" + container.getChildCount() + "++position:" + position);
                return view;
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(mViewList.get(position));
                Log.i(TAG, NAME + "--destroyItem++container:" + container.getChildCount() + "++position:" + position);
            }
    
        }
    
    }
    FragmentPagerAdapter

      该适配器最好用于有限个静态fragment页面的管理。尽管不可见的视图有时会被销毁,但用户所有访问过的fragment都会被保存在内存中。因此fragment实例会保存大量的各种状态,这就造成了很大的内存开销。
      使用该适配器,ViewPager在进行Fragment界面切换时,会将超过缓存数的界面销毁,但不销毁数据,即调用Fragment的onDestoryView方法,所有创建过的Fragment都会被保留。

    主要方法详解
    • public abstract Fragment getItem (int position)
      返回position位置关联的Fragment。
      FragmentPagerAdapter会将所有生成的 Fragment 对象通过 FragmentManager 保存起来备用,以后需要该 Fragment 时,都会从 FragmentManager 读取,而不会再次调用 getItem() 方法。该方法只有在创建新的Fragment时才调用。
      在需要时,该函数将被 instantiateItem() 所调用。
      如果需要向 Fragment 对象传递相对静态的数据时,我们一般通过 Fragment.setArguments() 来进行,这部分代码应当放到 getItem()。它们只会在新生成 Fragment 对象时执行一遍。
    • public long getItemId (int position)
      返回给定位置项的唯一标识。
    • public Object instantiateItem (ViewGroup container, int position)
      该方法每次生成缓存页面之外的Fragment时都会调用,这里的Fragment可能是新的生成,也可能是恢复。
      函数中判断一下要生成的Fragment是否已经生成过了,如果生成过了,就使用旧的,旧的将被Fragment.attach();如果没有,就调用getItem()生成一个新的,新的对象将被FragmentTransation.add()
      FragmentPagerAdapter会将所有生成的Fragment对象通过FragmentManager保存起来备用,以后需要该Fragment时,都会从FragmentManager读取,而不会再次调用getItem()方法。
      如果需要在生成Fragment对象后,将数据集中的一些数据传递给该Fragment,这部分代码应该放到这个函数的重载里。在我们继承的子类中,重载该函数,并调用FragmentPagerAdapter.instantiateItem()取得该函数返回 Fragment 对象,然后,我们该Fragment对象中对应的方法,将数据传递过去,然后返回该对象。
      否则,如果将这部分传递数据的代码放到getItem()中,在PagerAdapter.notifyDataSetChanged()后,这部分数据设置代码将不会被调用。
    • public void destroyItem(ViewGroup container, int position, Object object)
      超出缓存的页面,将调用该方法从视图中移除。
      该函数被调用后,会对Fragment进行FragmentTransaction.detach()。这里不是remove(),只是detach(),因此Fragment还在FragmentManager管理中,Fragment所占用的资源不会被释放。
    FragmentPagerAdapter使用示例

    FragmentPagerAdapterActivity.java文件

    /**
     * Created by sunxiaodong on 16/1/27.
     * 该适配器最好用于有限个静态fragment页面的管理。尽管不可见的视图有时会被销毁,但用户所有访问过的fragment都会被保存在内存中。因此fragment实例会保存大量的各种状态,这就造成了很大的内存开销。
     * 所以如果要处理大量的页面切换,建议使用FragmentStatePagerAdapter.
     */
    public class FragmentPagerAdapterActivity extends AppCompatActivity implements View.OnClickListener {
    
        private static final String NAME = FragmentPagerAdapterActivity.class.getSimpleName();
        private static final String TAG = "sxd";
    
        private ViewPager mViewPager;
        private MyFragmentPagerAdapter mMyFragmentPagerAdapter;
        private TextView mPageNum;
        private EditText mEditText;
        private Button mButton;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_pager_adapter);
            initView();
        }
    
        private void initView() {
            mViewPager = (ViewPager) this.findViewById(R.id.viewpager);
            mPageNum = (TextView) this.findViewById(R.id.page_num);
            mEditText = (EditText) this.findViewById(R.id.edit_text);
            mButton = (Button) this.findViewById(R.id.button);
            mButton.setOnClickListener(this);
    
            List<Fragment> fragments = new ArrayList<Fragment>();
            Fragment fragment1 = MyFragment.newInstance(1);
            Fragment fragment2 = MyFragment.newInstance(2);
            Fragment fragment3 = MyFragment.newInstance(3);
            Fragment fragment4 = MyFragment.newInstance(4);
            Fragment fragment5 = MyFragment.newInstance(5);
    
    
            fragments.add(fragment1);
            fragments.add(fragment2);
            fragments.add(fragment3);
            fragments.add(fragment4);
            fragments.add(fragment5);
    
            mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments);
            mViewPager.setAdapter(mMyFragmentPagerAdapter);
            mViewPager.addOnPageChangeListener(new OnMyPageChangeListener());//页面变化监听
            mViewPager.setOffscreenPageLimit(2);//设置缓存页面数。当前页,左右两边(单边)最大缓存页面数。
    //        mViewPager.setOnScrollChangeListener(new OnMyScrollChangeListener());//滚动状态监听,minSdkVersion:23
    //        mViewPager.getCurrentItem();//获取当前显示页索引
    //        mViewPager.getOffscreenPageLimit();//获取缓存页面数
    //        mViewPager.onSaveInstanceState();
    //        mViewPager.setPageTransformer();
            setPageNum(0);//设置显示首页
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    goPage();
                    break;
            }
        }
    
        private void goPage() {
            String pageNumStr = mEditText.getText().toString();
            if (pageNumStr == null || pageNumStr.isEmpty()) {
                return;
            }
            int pageNum = Integer.parseInt(pageNumStr);
            if (pageNum > 0 && pageNum <= mMyFragmentPagerAdapter.getCount()) {
                mViewPager.setCurrentItem(pageNum - 1);//设置当前显示页索引
            }
        }
    
        private void setPageNum(int position) {
            String pageNum = (position + 1) + "/" + mMyFragmentPagerAdapter.getCount();
            mPageNum.setText(pageNum);
        }
    
        /**
         * 页面变化监听器。
         * 三个方法的执行顺序为:用手指拖动翻页时,最先执行一遍onPageScrollStateChanged(1),然后不断执行onPageScrolled,放手指的时候,直接立即执行一次onPageScrollStateChanged(2),然后立即执行一次onPageSelected,然后再不断执行onPageScrollStateChanged,最后执行一次onPageScrollStateChanged(0)。
         */
        private class OnMyPageChangeListener implements ViewPager.OnPageChangeListener {
    
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                //position:当用手指滑动时,如果手指按在页面上不动,position和当前页面index是一致的;如果手指向左拖动(相应页面向右翻动),这时候position大部分时间和当前页面是一致的,只有翻页成功的情况下最后一次调用才会变为目标页面;如果手指向右拖动(相应页面向左翻动),这时候position大部分时间和目标页面是一致的,只有翻页不成功的情况下最后一次调用才会变为原页面。
                //当直接设置setCurrentItem翻页时,如果是相邻的情况(比如现在是第二个页面,跳到第一或者第三个页面),如果页面向右翻动,大部分时间是和当前页面是一致的,只有最后才变成目标页面;如果向左翻动,position和目标页面是一致的。这和用手指拖动页面翻动是基本一致的。
                //如果不是相邻的情况,比如我从第一个页面跳到第三个页面,position先是0,然后逐步变成1,然后逐步变成2;我从第三个页面跳到第一个页面,position先是1,然后逐步变成0,并没有出现为2的情况。
                //positionOffset:当前页面滑动比例,如果页面向右翻动,这个值不断变大,最后在趋近1的情况后突变为0。如果页面向左翻动,这个值不断变小,最后变为0。
                //positionOffsetPixels:当前页面滑动像素,变化情况和positionOffset一致。
                Log.i(TAG, NAME + "--onPageScrolled++position:" + position + ",++positionOffset:" + positionOffset + ",++positionOffsetPixels:" + positionOffsetPixels);
            }
    
            @Override
            public void onPageSelected(int position) {
                //position是被选中页面的索引,该方法在页面被选中或页面滑动足够距离切换到该页手指抬起时调用。
                Log.i(TAG, NAME + "--onPageSelected++position:" + position);
                setPageNum(position);
            }
    
            @Override
            public void onPageScrollStateChanged(int state) {
                //这个方法在手指操作屏幕的时候发生变化。有三个值:0(END),1(PRESS) , 2(UP) 。
                //当用手指滑动翻页时,手指按下去的时候会触发这个方法,state值为1,手指抬起时,
                //如果发生了滑动(即使很小),这个值会变为2,然后最后变为0 。总共执行这个方法三次。
                //一种特殊情况是手指按下去以后一点滑动也没有发生,这个时候只会调用这个方法两次,state值分别是1,0 。
                //当setCurrentItem翻页时,会执行这个方法两次,state值分别为2 , 0 。
                Log.i(TAG, NAME + "--onPageScrollStateChanged++state:" + state);
            }
        }
    
        /**
         * Fragment页面适配器
         * ViewPager在进行Fragment界面切换时,会将超过缓存数的界面销毁,但不销毁数据,即调用Fragment的onDestoryView方法
         * 所有创建过的Fragment都会被保留
         */
        private class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    
            private List<Fragment> mFragments;
    
            MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
                super(fm);
                mFragments = fragments;
            }
    
            @Override
            public Fragment getItem(int position) {
                //FragmentPagerAdapter 会将所有生成的 Fragment 对象通过 FragmentManager 保存起来备用,以后需要该 Fragment 时,
                // 都会从 FragmentManager 读取,而不会再次调用 getItem() 方法。该方法只有在创建新的Fragment时才调用。
                //1. 在需要时,该函数将被 instantiateItem() 所调用。
                //2. 如果需要向 Fragment 对象传递相对静态的数据时,我们一般通过 Fragment.setArguments() 来进行,这部分代码应当放到 getItem()。它们只会在新生成 Fragment 对象时执行一遍。
                Log.i(TAG, NAME + "--getItem++position:" + position);
                return mFragments.get(position);
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                //该方法每次生成缓存页面之外的Fragment时都会调用,这里的Fragment可能是新的生成,也可能是恢复
                //1.函数中判断一下要生成的 Fragment 是否已经生成过了,如果生成过了,就使用旧的,旧的将被 Fragment.attach();如果没有,就调用 getItem() 生成一个新的,新的对象将被 FragmentTransation.add()。
                //2. FragmentPagerAdapter 会将所有生成的 Fragment 对象通过 FragmentManager 保存起来备用,以后需要该 Fragment 时,都会从 FragmentManager 读取,而不会再次调用 getItem() 方法。
                //3. 如果需要在生成 Fragment 对象后,将数据集中的一些数据传递给该 Fragment,这部分代码应该放到这个函数的重载里。在我们继承的子类中,重载该函数,并调用 FragmentPagerAdapter.instantiateItem() 取得该函数返回 Fragment 对象,然后,我们该 Fragment 对象中对应的方法,将数据传递过去,然后返回该对象。
                //否则,如果将这部分传递数据的代码放到 getItem()中,在 PagerAdapter.notifyDataSetChanged() 后,这部分数据设置代码将不会被调用。
                Log.i(TAG, NAME + "--instantiateItem++container:" + container.getChildCount() + "++position:" + position);
                return super.instantiateItem(container, position);
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                //超出缓存的页面,将调用该方法从视图中移除
                //该函数被调用后,会对 Fragment 进行 FragmentTransaction.detach()。这里不是 remove(),只是 detach(),因此 Fragment 还在 FragmentManager 管理中,Fragment 所占用的资源不会被释放。
                Log.i(TAG, NAME + "--destroyItem++container:" + container.getChildCount() + "++position:" + position);
                super.destroyItem(container, position, object);
            }
    
            @Override
            public int getCount() {
                Log.i(TAG, NAME + "--getCount++");
                return mFragments.size();
            }
        }
    
    }
    FragmentStatePagerAdapter

      该适配器适合处理大量的页面切换,其能能够保存和恢复Fragment状态的适配器,超出缓存的Fragment会调用onDestory()方法,彻底对销毁Fragment进行销毁。

    主要方法详解
    • public Fragment getItem(int position)
      返回position位置关联的Fragment。
      该方法在滑到已经缓存的页面时,并不被调用。缓存外已经创建过并被销毁的页面,还会再调用该方法,重新创建。
    • public Object instantiateItem(ViewGroup container, int position)
      除非碰到FragmentManager刚好从SavedState中恢复了对应的Fragment的情况外(从页面缓存中恢复),该函数将会调用getItem()函数,生成新的Fragment对象。新的对象将被FragmentTransaction.add()
    • public void destroyItem(ViewGroup container, int position, Object object)
      超出缓存的页面,将调用该方法从视图中移除。
    FragmentStatePagerAdapter使用示例
    /**
         * 能够保存和恢复Fragment状态的适配器
         * 超出缓存的Fragment会调用onDestory()方法,彻底对销毁Fragment进行销毁
         */
        class MyFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
    
            private List<Fragment> mFragments;
    
            MyFragmentStatePagerAdapter(FragmentManager fm, List<Fragment> fragments) {
                super(fm);
                mFragments = fragments;
            }
    
            @Override
            public Fragment getItem(int position) {
                //该方法在滑到已经缓存的页面时,并不被调用。缓存外已经创建过并被销毁的页面,还会再调用该方法,重新创建。
                Log.i(TAG, NAME + "--getItem++position:" + position);
                return mFragments.get(position);
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                //除非碰到 FragmentManager 刚好从 SavedState 中恢复了对应的 Fragment 的情况外(从页面缓存中恢复),该函数将会调用 getItem() 函数,生成新的 Fragment 对象。新的对象将被 FragmentTransaction.add()。
                Log.i(TAG, NAME + "--instantiateItem++container:" + container.getChildCount() + "++position:" + position);
                return super.instantiateItem(container, position);
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                //超出缓存的页面,将调用该方法从视图中移除
                Log.i(TAG, NAME + "--destroyItem++container:" + container.getChildCount() + "++position:" + position);
                super.destroyItem(container, position, object);
            }
    
            @Override
            public int getCount() {
                Log.i(TAG, NAME + "--getCount++");
                return mFragments.size();
            }
        }

    源码地址

    展开全文
  • viewpager

    2019-06-03 09:17:24
    描述:viewpager+fragment,fragment会由fragmentManager进行管理,viewpager会从fragmentmanager中取fragment,即使list更新,数据也不会更新。fragmentmanager中是否存在已有的fragent主要是根据给fragment设置的...
  • Android ViewPager使用详解

    万次阅读 多人点赞 2014-08-12 15:59:25
    viewpager就是其中之一利用它,我们可以做很多事情,从最简单的导航,到页面菜单等等。那如何使用它呢,与LisstView类似,我们也需要一个适配器,他就是PagerAdapter。看一下api的图片, ViewPager的功能就是可以...
  • ViewPager 全面总结

    万次阅读 多人点赞 2019-07-17 13:48:44
    Viewpager,视图翻页工具,提供了多页面切换的效果。Android 3.0后引入的一个UI控件,位于v4包中。低版本使用需要导入v4包,但是现在我们开发的APP一般不再兼容3.0及以下的系统版本,另外现在大多数使用Android ...
  • ViewPager

    千次阅读 2017-09-21 10:09:25
    ViewPager 一、ViewPager简介: (一)、作用: ViewPager的功能就是可以使视图滑动,就像Lanucher左右滑动那样。ViewPager用于实现多页面的切换效果。该类存在于Google的兼容包里面,android.support.v4...
  • ViewPager 详解(二)---详解四大函数

    万次阅读 多人点赞 2019-09-11 15:38:30
    前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合android...3、《ViewPager 详解(三)-...
  • ViewPager 详解(五)-----使用Fragment实现ViewPager滑动

    万次阅读 多人点赞 2019-09-11 15:39:51
    前言:前几篇文章讲解了ViewPager的普通实现方法,但android官方最推荐的一种实现方法却是使用fragment,下面我们使用fragment来重新实现一下第一篇《ViewPager 详解(一)---基本入门》所实现的效果。 系列文章...
  • ViewPager,ScrollView 嵌套ViewPager滑动冲突解决

    万次阅读 多人点赞 2019-06-16 23:22:45
    ViewPager,ScrollView 嵌套ViewPager滑动冲突解决这篇博客主要讲解一下几个问题 - 粗略地介绍一下View的事件分发机制 - 解决事件滑动冲突的思路及方法 - ScrollView 里面嵌套ViewPager导致的滑动冲突 - ...
  • 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40411921,本文出自:【张鸿洋的...有兄弟提出,ViewPager自带了一个setPageTransformer用于设置切换动画~本篇博文,将:1、介绍如何使用setPageTr
  • ViewPager加载Activity

    千次下载 热门讨论 2020-07-19 23:31:38
    ViewPager滑动切换Activity,类似于新浪微博的消息模块
  • BottomNavigationView+ViewPager+Fragment 底部导航按钮

    万次阅读 多人点赞 2020-01-23 19:31:45
    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主威威喵原创,请多支持与指教。 ... 感受 Material Design UI 魅力,你不能错过的Material Design 全系列文章: ...Material Design 之一 ...
  • Android照片墙加强版,使用ViewPager实现画廊效果

    万次阅读 多人点赞 2016-10-19 00:47:00
    记得关于照片墙的文章我已经写过好几篇了,有最基本的照片墙,有瀑布流模式的照片墙,后来又在瀑布流的基础之上加入了查看大图和多点触控缩放的功能。总体来说,照片墙这个Demo在这几篇文章的改进中已经变得较为完善...
  • Android 自定义 ViewPager 打造千变万化的图片切换效果

    万次阅读 多人点赞 2016-08-10 19:34:01
    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 记得第一次见到ViewPager这个控件,瞬间...时间长了,ViewPager的切换效果觉得枯燥,形成了审美疲劳~~我们需要改变,今天教大家如
  • 官方 Viewpager 升级版 - ViewPager2 实战

    万次阅读 2019-03-31 10:23:52
    Google 在 `androidx` 组件包里增加了一个新的组件 `ViewPager2`,目前已经更新了两个 alpha 版本了。那么,和之前的 `ViewPager` 组件相比,有什么改进呢?查看[官方文档]
  • ViewPager 详解(四)----自主实现滑动指示条

    万次阅读 多人点赞 2019-09-11 15:39:10
    前言:前面我们用了三篇的时间讲述了有关ViewPager的基础知识,到这篇就要进入点实际的了。在第三篇《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》中,我们说了,PagerTabStrip和...
  • 我知道你会用ViewPager,可你在ViewPager中用过Android5.0新控件CardView么?你用过PageTransformer属性吗?搞懂这几个,让你的ViewPager大放异彩!
1 2 3 4 5 ... 20
收藏数 61,385
精华内容 24,554
关键字:

viewpager