需求
在操作ViewPager
时,需要知道Fragment
对用户展示、隐藏的时刻。
背景
因为ViewPager
通过 setOffscreenPageLimit
提供预加载的功能,所以传统生命周期的onResume()
、onPause()
不能准确的表达Fragment对用户是否可见。
传统的做法是给ViewPager
的onPageSelect()
事件里,发送一个广播,通知Fragment
当前页发生了变化。Fragment
对比自身position
和广播携带的参数position
是否一致,判断自己是否当前页,以此来执行 展示、隐藏操作。
优化
Fragment的生命周期里,提供了一个setUserVisibleHint(boolean isVisibleToUser)
函数。它的作用是告诉系统Fragment是否对用户可见,使用场景是在ViewPager
的适配器FragmentStatePagerAdapter
和FragmentStatePagerAdapter
我们看下引用这个函数的地方
- 实例化Fragment
@Override
public Object instantiateItem(ViewGroup container, int position) {
//....创建Fragment操作....
if (fragment != mCurrentPrimaryItem) {
//....其他操作....
//不是当前页,则设置hint为flase
fragment.setUserVisibleHint(false);
}
return fragment;
}
- 设置Fragment为当前项
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
//....其他操作....
//老的设置为不可见
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
//....其他操作....
//新的设置为可见
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
需要注意的是,setUserVisibleHint()
和Fragment
的生命周期是没关联的的。
setUserVisibleHint,在ViewPager
左右滑动的时候,因为预加载的机制,所以页面已经初始化好;
但是通过setCurrentItem(页码);
跳到某个页面时,此时页面还未初始化。
我们业务里面的操作,需要页面布局已经完成,因此在使用它的时候,我们需要额外的技巧,下面修改后的XLBaseFragment
子类重写 showToUserInViewPager
和hideToUserInViewPager()
即可
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//状态如果一致,则不去做操作
if (mIsShowToUser == isVisibleToUser) return;
//从隐藏切到显示
if (isVisibleToUser) {
if (mIsViewInitial) {
showToUserInViewPager();
mRemainShowEventToTake = false;
} else {
mRemainShowEventToTake = true;
}
} else {
//从显示切到隐藏
hideToUserInViewPager();
}
mIsShowToUser = isVisibleToUser;
}
@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//一些操作。。
if (mRemainShowEventToTake && getUserVisibleHint()) {
mRemainShowEventToTake = false;
showToUserInViewPager();
}
}