需求描述:学习中心—-有个两个pager,一个参加的课程,一个参加的微专业。每个pager要求用fragment实现。最外层是一个ViewPager控件。可以实现下拉刷新功能,如果微专业列表为null,只显示参加的课程;不为null则显示两个pager页。
分析需求,这里需要实现的是FragmentPagerAdapter.notifyDataSetChange()可以更新fragment的数量,有时候可以显示两个,有时候一个,每次刷新可能都会不同。
简单的用正常手段去实现ViewPager+FragmentPagerAdapter去实现,发现无法做到刷新更新fragment的数量的问题。这里需要结合源码做一些特殊处理。
先看我写的adapter:
private classCourseEnrolledFragmentAdapterextendsFragmentPagerAdapter {
publicCourseEnrolledFragmentAdapter(FragmentManager fm) {
super(fm);
}
@Override
publicFragment getItem(inti) {
if(i <mPageList.size()) {
returnmPageList.get(i);
}
return null;
}
@Override
public intgetCount() {
returnmPageList.size();
}
@Override
public intgetItemPosition(Object object) {
if(mPageList!=null&& !mPageList.isEmpty()) {
if(!mPageList.contains(object)) {
returnPOSITION_NONE;
}
}
returnPOSITION_UNCHANGED;
}
@Override
public longgetItemId(intposition) {
returnmPageList.get(position).getFragmentId();
}
@Override
publicCharSequence getPageTitle(intposition) {
if(mTabNames!=null&&mTabNames.length> position) {
returnmTabNames[position];
}
return super.getPageTitle(position);
}
}
这里我重写了getItemPosition方法,mPageList是一个fragment的ArrayList。当需要remove掉其中一个Fragment的时候,让getItemPosition返回POSITION_NONE,意思是该位置的pager已经不存在了,需要destoryItemview方法,然后重新getItem。默然返回的是POSITION_UNCHANGED,pager没变化,不会刷新当前的pager。
做完这一步之后发现,的确刷新后可以隐藏掉该fragment,
mPageList.remove(mFragmentMicroSpecial);
mFragmentAdapter.notifyDataSetChanged();
但是如果再刷新又需要显示该fragment的话,然后就出问题了。因为在FragmentPagerAdapter源码里面
publicObject instantiateItem(ViewGroup container,intposition) {
if(this.mCurTransaction ==null) {
this.mCurTransaction =this.mFragmentManager.beginTransaction();
}
longitemId =this.getItemId(position);
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment =this.mFragmentManager.findFragmentByTag(name);
if(fragment !=null) {
this.mCurTransaction.attach(fragment);
}else{
fragment =this.getItem(position);
this.mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId));
}
if(fragment !=this.mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
returnfragment;
}
findFragmentByTag的方式去查找之前的fragment,发现之前remove的fragment不为null,然后又将之前remove掉的fragment attach到view pager里面。但是界面数据并没有刷新,还是用remove前的数据。
所以,我总结出的方法就是,如果要更新FragmentPagerAdapter里的fragment,不仅仅是remove掉该Fragment,还应该给该fragment赋null。这样如果需要再次显示该fragment就不会出问题。当然前提是你有用POSITION_NONE去做处理。这还得根据具体业务需求来做。
细心的朋友可能会发现我这里重写了下面的方法
@Override
public longgetItemId(intposition) {
returnmPageList.get(position).getFragmentId();
}
系统默认返回的是position。
之前有个需求要求参加前的fragment pagers是“介绍”、“评价”,点击参加后fragment pagers要变成“目录”,“公告”。再退选又变回来。这些pagers都是不同的fragment实现的。在当前activity去做更新。
好吧,如果遇到这种需求,你会发现上面重写的方法自己实现会帮助到你。因为源码里的实现是
longitemId =this.getItemId(position);
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment =this.mFragmentManager.findFragmentByTag(name);
具体不多说,还是多看源码,根据具体需求设计更合适的实现方案。