ViewPager笔记

1.FragmentStatePageAdapter和FragmentPageAdapter的异同点
同:

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

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

(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)关于FragmentAdapter的写法

//写法1:容易引起内存泄露
//不管使用哪种adapter,都只是销毁了视图而已,Fragment并不会被回收,因为adapter中的mFragmentList 
//引用着Fragment。

public class FragmentAdapter4 extends FragmentStatePagerAdapter {


    private List<Fragment> mFragmentList;

    public FragmentAdapter4(FragmentManager fm, List<Fragment> fragmentList) {
        super(fm);
        mFragmentList = fragmentList;
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        if (mFragmentList == null) {
            return 0;
        }
        return mFragmentList.size();
    }
}
//写法2:正确写法
//在getItem中去构造Fragment

public class FragmentAdapter2 extends FragmentStatePagerAdapter {

    private int[] mArrayRes;

    public FragmentAdapter2(FragmentManager fm, int[] arrayRes) {
        super(fm);
        mArrayRes = arrayRes;
    }

    @Override
    public Fragment getItem(int position) {
        return StateFragment.newInstance(mArrayRes[position]);
    }

    @Override
    public int getCount() {
        if (mArrayRes == null) {
            return 0;
        }
        return mArrayRes.length;
    }
}

(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.youkuaiyun.com/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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值