1.实现循环切换
思路一:在ViewPager的Adapter中返回count的值为 Integer.MAX_VALUE ,进行初始化的时候讲ViewPager的 setCurrentItem(int item) 的方法中传入Integer.MAX_VALUE的一个中间值,因为Int的最大值是2147483647 如果设它的中间值用户是很难滑到两端的,但是并意味着不能滑到两端。
思路二:在item的两端各增加一个Item,当ViewPager滑动到第一个Item的时候跳转到倒数第二Item,当滑动到最后一个Item时候跳转到第二个Item,设置跳转的方法一定要用
public void setCurrentItem(int item, boolean smoothScroll)
传递参数为false ,这样跳转的就会很流畅。
部分实现代码
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
removeCheck();
Log.i(TAG, "onPageScrolled: positionOffset = "+positionOffset+ ", positionOffsetPixels = "+positionOffsetPixels);
}
@Override
public void onPageSelected(int position) {
RceLog.i(TAG, "onPageSelected() position : " + position);
if (position == 0) {
isChange = true;
tabIndex = moduleList.size() - 2;
} else if (position == moduleList.size() - 1) {
isChange = true;
tabIndex = 1;
} else {
tabIndex = position;
}
}
@Override
public void onPageScrollStateChanged(int state) {
Log.i(TAG, "onPageScrollStateChanged: state = "+state);
if (state == ViewPager.SCROLL_STATE_IDLE) {
if (isChange) {
isChange = false;
viewPager.setCurrentItem(tabIndex, false);
}
}
}
2.禁止预加载问题
看了一下网上的解决方案,不少人都建议使用ViewPager的setOffscreenPageLimit(int limit),但是通过查看源码发现要禁止预加载使用该方法是无效的。
private static final int DEFAULT_OFFSCREEN_PAGES = 1;
public void setOffscreenPageLimit(int limit) {
if (limit < DEFAULT_OFFSCREEN_PAGES) {
Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
+ DEFAULT_OFFSCREEN_PAGES);
limit = DEFAULT_OFFSCREEN_PAGES;
}
if (limit != mOffscreenPageLimit) {
mOffscreenPageLimit = limit;
populate();
}
}
从上面的源码可以明显的看出,使用该方法根本行不通,通过他设置预加载界面至少为一个界面,所以怎么设置都会预加载的。
方案二:
在Fagment可见的时候在进行加载数据,重写setUserVisibleHint(boolean isVisibleToUser)方法 进行判断当前Fragment是否可见
public abstract class BaseFragment extends Fragment {
protected boolean isUserVisible;
protected boolean isPrepared;//标志已经初始化完成
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
isUserVisible = true;
onUserVisible();
} else {
isUserVisible = false;
onUserInvisible();
}
}
/**
* fragment 可见
*/
protected void onUserVisible() {
if (isPrepared && isUserVisible && isAdded()) {
update();
}
}
/**
* fragment 不可见
*/
protected void onUserInvisible() {
}
/**
* 子类重写此方法,在fragment 可见的时候更新 UI
*/
protected abstract void update();
}
子类在重写update方法,在update中进行数据更新
3.FragmentPagerAdapter与FragmentStatePagerAdapter
FragmentPagerAdapter:对于不再需要的fragment,选择调用detach方法,仅销毁视图,并不会销毁fragment实例。再次加载的时候时调用attach方法
destroyItem 的处理
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
if (this.mCurTransaction == null) {
this.mCurTransaction = this.mFragmentManager.beginTransaction();
}
this.mCurTransaction.detach((Fragment)object);
}
再次加载时instantiateItem 中的部分代码
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));
}
FragmentStatePagerAdapter:会调用remove方法销毁不再需要的fragment,当当前事务提交以后,会彻底的将fragmeng从当前Activity的FragmentManager中移除,state标明,销毁时,会将其onSaveInstanceState(Bundle outState)中的bundle信息保存下来,当用户切换回来,可以通过该bundle恢复生成新的fragment,也就是说,你可以在onSaveInstanceState(Bundle outState)方法中保存一些数据,在onCreate中进行恢复创建。
destroyItem 的处理:调用FragmentTransaction的remove方法从FragmentManager中移除Fragment,同时在mSaveState中保存了Fragment的状态。
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment)object;
if (this.mCurTransaction == null) {
this.mCurTransaction = this.mFragmentManager.beginTransaction();
}
while(this.mSavedState.size() <= position) {
this.mSavedState.add((Object)null);
}
this.mSavedState.set(position, fragment.isAdded() ? this.mFragmentManager.saveFragmentInstanceState(fragment) : null);
this.mFragments.set(position, (Object)null);
this.mCurTransaction.remove(fragment);
}
再次加载的时候回从mSavedState获取状态,设置给Fragment
instantiateItem(@NonNull ViewGroup container, int position) 中的部分代码
fragment = this.getItem(position);
if (this.mSavedState.size() > position) {
SavedState fss = (SavedState)this.mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
通过两个Adapter的对比FragmentPagerAdapter没一个Fragment都会保存在内存中,因此使用一些页面较少的情况,如果界面比较多的情况应该使用FragmentStatePagerAdapter。