ViewPager笔记

来源:互联网 发布:java 按位异或 编辑:程序博客网 时间:2024/05/19 23:57

1.FragmentStatePageAdapter和FragmentPageAdapter的异同点
同:

(1)对于超出缓存范围的Fragment:
FragmentStateAdapter执行Fragment的onDetach,即超出缓存的范围,Fragment将才从Activity中脱离(detach),当然此时Fragment的视图也会被销毁。
FragmentAdapter执行onDestroyView ,超出缓存的范围,Fragment将销毁视图,但是不会从Activity中脱离(detach)

(2)使用FragmentStatePageAdapter,当Fragment销毁时,会将其onSaveInstanceState(Bundle outState)中的bundle信息保存下来,当用户切换回来,可以通过该bundle恢复生成新的fragment,也就是说,你可以在onSaveInstanceState(Bundle outState)方法中保存一些数据,在onCreate中进行恢复创建。

(3)注意:
1)onDestroyView可以理解为切断了Fragment到View的引用,如果此时View没有被其他东西引用,那么这个View将等待GC回收,表现在你下次回来这个Fragment的时候,将执行onCreateView来重建View(如EditText,ImageView都是要重新创建的)。
反之这个View中的某些子View将不会被回收。比如下面的代码:

 private ImageView imageView;  @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        // Inflate the layout for this fragment        super.onCreateView( inflater, container,                savedInstanceState);        View view= inflater.inflate(R.layout.fragment_fragment_one, container, false);         imageView= (ImageView) view.findViewById(R.id.image_one);        return view;    }

如上面代码所示,因为成员变量imageView还保持对View中ImageView的引用,所以ImageView占用的内存并不会被回收。要是的ImageView被回收,采用如下代码

 @Override    public void onDestroyView() {        super.onDestroyView();        imageView=null;    }

2)onDetach意思是Fragment从Activity脱离,此时若在Fragment中调用getActivity()将得到null。
3)不管使用哪种adapter,都只是销毁了视图而已,Fragment并不会被回收,因为adapter中的list 引用着Fragment。

(2)都是默认缓存3个,setOffscreenPageLimit(int num)设置缓存的个数。
(3)各个重要方法的作用和执行顺序。(从上到下按顺序)
左右滑动时:
onPageScrollStateChanged DRAGGING
onPageScrollStateChanged SETTLING
onPageSelected
onPageScrollStateChanged IDLE
setPrimaryItem (会执行多次)

初始化时:
getCount
getItem
setPrimaryItem(会先setPrimaryItem,再预加载,所以当第一次加载的时候,会先setPrimaryItem,再加载当前的Fragment)
Fragment的生命周期一定在getItem之后,但是多个Fragment的生命周期有可能是交替执行的。

这里写图片描述

2.给ViewPager设置切换动画:

public class BasePagerTransFarmer implements ViewPager.PageTransformer  {    private static float MIN_SCALE = 0.75f;    @SuppressLint("NewApi")    @Override    public void transformPage(View view, float position) {        int pageWidth = view.getWidth();        if (position < -1) { // [-Infinity,-1)            // This page is way off-screen to the left.            view.setAlpha(0);        } else if (position <= 0) { // [-1,0]            // Use the default slide transition when            // moving to the left page            view.setAlpha(1);            view.setTranslationX(0);            view.setScaleX(1);            view.setScaleY(1);        } else if (position <= 1) { // (0,1]            // Fade the page out.           view.setAlpha(1 );            // Counteract the default slide transition            view.setTranslationX(pageWidth * -position);            // Scale the page down (between MIN_SCALE and 1)            float scaleFactor = MIN_SCALE + (1 - MIN_SCALE)                    * (1 - Math.abs(position));            view.setScaleX(scaleFactor);            view.setScaleY(scaleFactor);        } else { // (1,+Infinity]            // This page is way off-screen to the right.            view.setAlpha(0);        }    }    }
//设置动画viewPager.setPageTransformer(true, new BasePagerTransFarmer()); 

更多切换动画内容请点
http://blog.csdn.net/angcyo/article/details/49796759

3.使用PagerAdapter需实现一下四个方法:
getCount
isViewFromObject
instantiateItem
destroyItem

而FragmentStatePageAdapter和FragmentPageAdapter只需实现
getCount和getItem,其他方法已经帮我们实现好了。

4.
设置页卡间距: viewPager.setPageMargin(30);(或者用 viewPager.setPageMargin(-30),这样可以在一个pager里看到到两个pager放在一起的效果。)

5.
ViewPager无限轮播
方法1:
特殊说明:只有两条(a,b),一条数据(a)时,往list中添加相同的数据即可(a,b,a,b),(a,a,a)

 @Override    public Object instantiateItem(ViewGroup container, int position) {           container.addView(viewList.get(position%viewList.size()));           return viewList.get(position%viewList.size());    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {     container.removeView(viewList.get(position%viewList.size()));    }    @Override    public int getCount() {        return Integer.MAX_VALUE;    }

方法2:
特殊说明:只有一条数据时(a),往list中再添加两条相同数据即可(a,a,a)

这里写图片描述

    boolean mIsChanged;//标识是否需要在onPageScrollStateChanged中重新setCurrentItem    int pageIndex;    @Override    public void onPageScrollStateChanged(int pState) {        if (ViewPager.SCROLL_STATE_IDLE == pState) {//viewpager已经停止滑动            if (mIsChanged) {                mIsChanged = false;                mViewPager.setCurrentItem(pageIndex, false);            }        }    }    @Override    public void onPageSelected(int position) {        if (position == 0) {            // 当视图在第一个时,将页面号设置为图片的最后一张。            mIsChanged=true;            pageIndex = mViewPagerList.size() - 2;        } else if (position == mViewPagerList.size() - 1) {            // 当视图在最后一个时,将页面号设置为图片的第一张。            mIsChanged=true;            pageIndex = 1;        }        /**         * 不要在此处  mViewPager.setCurrentItem(pageIndex, false); 因为此时viewpager还没有停止滑动,会造成界面闪跳         */    }

6.自定义ViewPager的滑动速度。
(1)自定义一个Scroller类

public class FixedScroller extends Scroller {    private int mDuration = 500;    public FixedScroller(Context context) {        super(context);    }    public FixedScroller(Context context, Interpolator interpolator) {        super(context, interpolator);    }    @Override    public void startScroll(int startX, int startY, int dx, int dy, int duration) {       //用mDuration去代替系统默认的Duration        super.startScroll(startX, startY, dx, dy, mDuration);    }    @Override    public void startScroll(int startX, int startY, int dx, int dy) {   //用mDuration去代替系统默认的Duration        super.startScroll(startX, startY, dx, dy, mDuration);    }}
 try {  //使用反射重新设置ViewPager的Scroller            Field mScroller;            mScroller = ViewPager.class.getDeclaredField("mScroller");            mScroller.setAccessible(true);            Interpolator sInterpolator = new LinearInterpolator();            FixedScroller scroller = new FixedScroller(viewPager.getContext(),                    sInterpolator);            mScroller.set(viewPager, scroller);        } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {        }

7.关于adapter的 notifyDataSetChanged()
(1)当adapter中的数据源发生变化的时候(list的size变化了,list里面的内容变化了),就需要调用notifyDataSetChanged()去更新数,否则应用会崩溃。要注意两点:

a.如果只是list的size变化了,就不用重写adapter的getItemPosition()。

b.如果是list里面的内容变化了,就需要重写adapter的getItemPosition()

public int getItemPosition(Object object) {        // 对应position的pager不需要更新,这是默认值        //return POSITION_UNCHANGED;         //需要更新        return POSITION_NONE;    }

8.destroyItem和instantiateItem 源码解析

如果destroyItem没有删除viewpager,那么instantiateItem就不会去调用getItem来获取新的fragment,而是复用之前的fragment。

如果如果destroyItem删除了viewpager,那么instantiateItem就会去调用getItem来获取新的fragment。

0 0
原创粉丝点击