关于在ViewPager中添加Fragment的问题

来源:互联网 发布:zz的网络意思 编辑:程序博客网 时间:2024/05/21 07:10

我们在什么情况下能使用到这个呢?

一般的情况,ViewPager只需要简单的实现PagerAdapter即可。可是当你遇到这种情况,ViewPager中的View本身有着大量的数据处理工作,要调很多接口什么的,你会发现你脑子会炸的...

我遇到的情况是,我的上篇文章点击打开链接中的情况,上面有一个TabLayout可以滚动,而且下面的内容也可以滚动来切换Tab,所以我用的是TabLayout+ViewPager,这样可以实现动态的添加Tab(取决于后台返回的多少来添加),这个easy,可是下面的ViewPager如果要动态的添加,而且每一项的数据又不一样的时候,我发现传统的只是实现PagerAdapter是不行的,每一个子项里面有太多不一样的数据,我绞尽脑汁实现了一下,能实现效果,但是当你滚动的很快的时候他就崩了(发生IndexOutOfBounds异常)。

想了想,最好是能在Fragment中单独去处理数据,可是Fragment也不是View,该怎么添加到ViewPager中呢,尝试着去寻找答案,原来还有PagerAdapter的子类FragmentPagerAdapter!这个是什么?好像能解决问题!查阅资料得知,好像这个就是能向ViewPager中添加Fragment的适配器!先试试是不是吧。

果然,就是他!

//切换FragmentViewPagerprivate ViewPager mViewpager;//切换FragmentViewPager的适配器private MyFragPagerAdapter mFragPagerAdapter;//盛放要切换的所有fragment(只需要定义一个Fragment类就可),按照getArgument()去获取不同的数据private List<android.support.v4.app.Fragment> mFragments;
看定义:

private class MyFragPagerAdapter extends FragmentPagerAdapter {    private List<android.support.v4.app.Fragment> fragments;    public MyFragPagerAdapter(FragmentManager fm, List<android.support.v4.app.Fragment> mFragments) {        super(fm);        fragments = mFragments;    }    @Override    public android.support.v4.app.Fragment getItem(int position) {        return fragments.get(position);    }    @Override    public int getCount() {        return fragments.size();    }}
而且他的getItem只能返回v4兼容包下的Fragment,不能返回android.app.Fragment下的fragment,而且一路发现和fragment相关的都是v4包下的,即使是构造方法里要用的FragmentManager也得是v4包下的,而且在fragment中无法获取v4包下的FragmentManager(getSupportFragmentManager()方法来取),哪怕是getActivity().getSupportFragmentManager()也不行,所以要在他的上下文Activity中定义成static型的,而且不同的两个Activity下的v4包下的FragmentManager也不能公用,并且必须是AppCompatActivity环境下才能获取到。

//v4包下的FragmentManagerpublic static android.support.v4.app.FragmentManager sV4FragManager ;
然后在fragment中取

mFragPagerAdapter = new MyFragPagerAdapter(Main.sV4FragManager, mFragments);
这样就可以实现了。

注意,要先将ViewPager要显示的Fragment集合给初始化,然后再设置tab的内容,要不然提前设置会被清空(和ViewPager绑定之后会被remove掉然后添加了新的)。所以

/*    ViewPager初始化要添加的View*/private void addAllViews() {    for (int i = 0; i < mTitles.size(); i++) {        android.support.v4.app.Fragment fragment = new Child_SingleTab();        Bundle bundle = new Bundle();        bundle.putString("categoryId", (String) mTitles.get(i).get("categoryId"));        fragment.setArguments(bundle);        mFragments.add(fragment);    }    mFragPagerAdapter.notifyDataSetChanged();    //此时Tab的标题被覆盖了,需要重新设置    for (int i = 0; i < mFragments.size(); i++) {        mTabLayout.getTabAt(i).setText((String) mTitles.get(i).get("categoryName"));    }}
那么初始化的View数是多少呢,我们前面说过,接口去多少就添加多少,所以先调获取Tab的接口,然后得到他的数量。

final JSONObject jsobj = BaseDataService.getTabsData("1");//先得到标题mTitles = JsonUtils.parseJsonArray(jsobj.getJSONArray("results"));Main.sHandler.post(new Runnable() {    @Override    public void run() {        //ViewPager添加View        addAllViews();    }});
在取完后去调添加View的方法。

还有一个问题,我们说过,每一项的子View里面的数据和显示也不一样,我们的Fragment在这里只有一个,Fragment怎么知道当前是第几个Tab下的显示从而去获取不同的数据呢?想了一会,有了!

Bundle bundle = new Bundle();bundle.putString("categoryId", (String) mTitles.get(i).get("categoryId"));fragment.setArguments(bundle);
看上面的添加View的方法里,在添加每个fragment的时候加入arguments,在Fragment的onCreateView方法里去判断是第几个Tab,从而去获取不同的数据。哪怕如果像腾讯视频里的那样,有的布局都不一样都可以实现:只需要判断arguments,然后去inflate不同的布局即可!

bingo!!

还有一个FragmentStatePagerAdapter,据说它的意义在于:

之前我们知道

mViewpager.setOffscreenPageLimit(index);

这个方法可以设置显示之外的缓存页数,优点就是切换其他页的时候会不用现去初始化界面,只要显示过一次他会提前在内存中存在不会销毁,默认是显示页的左右两页缓存,当你的内存不够用时就可以用FragmentStatePagerAdapter了,只要是没在当前显示,立马销毁,不占用内存。

补充补充:

FragmentPagerAdapter中的数据集合要使用同一个指向,不能用中间指向,像上文中的fragments就不行。初始的mFragments改变并不会引起重绘(notifyDataSetChanged之后)。

如果想要启动另一个Activity,在fragment中调用startActivityForResult()之后会回调到此fragment的onActivityResult方法中,getActivity.startActivityForResult()之后会回调到Activity的onActivityResult方法中。

我想让回调时可以重新创建视图怎么办,replace试过了,不行,remove,add还是不行,标题是最新的了,但是下面的ViewPager的内容不显示或者显示混乱,跑了断点结果发现ViewPager里面的fragment根本没执行onCreateView方法!

也就是说Activity下的Fragment和其下的子Fragment都被移除了,但是ViewPager中的Fragment还没有被移除或者是冲突了!

解决方法是,每次onSaveInstanceState时都移除ViewPager的fragment集合里面的fragment,然后onResume的时候重新添加。

ps:

@Overridepublic void onSaveInstanceState(Bundle outState) {    android.support.v4.app.FragmentTransaction transactionV4 = Main.sV4FragManager.beginTransaction();    if (mFragments != null) {        for (int i = 0; i < mFragments.size(); i++) {            transactionV4.remove(mFragments.get(i));        }    }    transactionV4.commit();    mFragPagerAdapter.notifyDataSetChanged();    super.onSaveInstanceState(outState);}@Overridepublic void onResume() {    super.onResume();    //初始化    init();}

注意了!纠正!纠正!(此问题导致我2016-12-3留宿公司一宿)

1.我的情况是Activity里嵌套了Fragment_0,然后Fragment_0里面又嵌套了两个Fragment:Fragment_1、Fragment_2,然后我在其中一个Fragment,Fragment_1里面有一个包含一系列Fragment的ViewPager,按照前面的步骤没什么问题,数据也是对的,可是!可是!当我在另一个fragment,也就是Fragment_2里添加的和Fragment_1里面的一模一样,然后就有问题了,Tab能正常显示,点击切换也没什么问题,但是当你活动下面的ViewPager时,居然指示条滑动和标题不对应,有时候滑动2、3次才能切换标题,但是指示条每次只移动一点,这是我已经把ViewPager里面的fragment都给去了,要不然直接就甭,现实的错误信息是我ViewPager里面的fragment的下拉刷新出问题了,这都是由于先前的Fragment_1里面的fragment有没有销毁的导致的!!

结局方法就:我们前面说到,FragmentPagerAdapter的构造方法需要一个v4包下的FragmentManager,之前我是在上溯到Activity里面去取的,其实FragmentPagerAdapter的构造方法里要传进去的是getChildFragmentManager()获取到的FragmentManager,这个是专门供当前Fragment用的FragmentManager,必须要这样,要不然可能你当时没发现问题,后来有问题了就准备哭吧,然后还需要注意的是,getChildFragmentManager()这个方法是属于Fragment里面的方法,如果你在app包下调用这个方法那么获取的就是app包下的FragmengManager,反之,如果你在v4包下调用这个方法那么获取的就是v4包下的FragmengManager!

2.还有,同一个Activity下,不能同时使用v4包下的Fragment和app包下的Fragment!

3.大神说,如果使用的不是v4包下的Fragment,需要导入v11支持库用v11的FragmentPagerAdapter!(我想这种适用于有太多地方,改不过来的情况吧)

切记切记!!!








0 0
原创粉丝点击