我有一个ViewPager
有4个片段(a,b,c,d),c和d都有ViewPager
个,基本上是嵌套的视图寻呼机。我附上了一张图片来说明我的布局。因此,当我选择片段B时,setUserVisibleHint(boolean)
为true
且片段C中的setUserVisibleHint(boolean)
为false
,这是预期的行为。但是,即使片段C中的setUserVisibleHint(boolean)
为false
,片段C setUserVisibleHint(boolean)
中的第一个片段中的ViewPager
也为true
。
我不认为这是预期的行为。有人可以告诉你这里可能会发生什么吗?我非常感谢任何意见。
答案 0 :(得分:0)
From docs of setUserVisibleHint(boolean)
:
Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.
An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.
As can be outlined from the docs:
true
If you look into the usages of setUserVisibleHint(boolean)
, you'll see following list:
Thus, only PagerAdapter
implementations are calling that method.
As you have outlined, PagerAdapter
is correctly setting that flag for all the fragment that it possesses.
PagerAdapter
is non-wiser about child fragments, that fragment C has. It's not the responsibility of PagerAdapter
to set that flag for child fragment of fragment C. It's the responsibility of "the app" (in this case you) to manually set that boolean value.
答案 1 :(得分:0)
您应该检查父级是否为片段且可见或不为片段,然后开始逻辑。
public class Child1FragmentC extend Fragment {
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && isParentFragmentVisible())
//TODO: start your logic
}
/**
*
* @return true if the parent is fragment and visible or the parent isn't fragment
*/
boolean isParentFragmentVisible() {
return getParentFragment() == null || getParentFragment().getUserVisibleHint();
}
}
现在,当平台将调用片段C上的第一个片段时,它将询问它的父片段C,并且它是不可见的,因此不会启动它的逻辑。
另外,当片段C的可见性更改时,平台不会通知片段c的第一个片段其可见性已更改,这是因为平台之前已告知它,并且由于父级是不可见的,所以我们没有启动逻辑。
因此,我们需要在其可见性更改时制作片段c,以通知其视图分页器中的当前可见片段(片段C的第一个片段)可见性已更改。
public class FragmentC extend Fragment {
/**
* Notify the current selected fragment inside view pager that it's visibility changed.
*
* @param isVisibleToUser
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser)
//TODO: start your logic
//Notify the current fragment in view pager the the isVisibleToUser changed.
Fragment currentFragment = getChildFragmentManager().findFragmentByTag(
"android:switcher:" + getViewPagerId() + ":" + getViewPager().getCurrentItem());
if (currentFragment != null)
currentFragment.setUserVisibleHint(isVisibleToUser);
}
}
您应该处理的另一件事是在创建视图之前平台调用setUserVisibilityHint,因此您应该通过检查getView()!= null或任何其他条件来检查视图是否已准备就绪。
所以最终的代码将是这样。
public abstract class BaseFragment extend Fragment {
/**
* start logic if isVisibleToUser, isViewPrepared and isParentFragmentVisible equal true.
*
* => We check isViewPrepared equal true before starting logic because setUserVisibleHint
* called before all fragment lifecycle callbacks. So we should check if the view is
* prepared.
*
* => We check if the parent is visible to solve if we have a fragment inside a view pager and
* that fragment also has view pager that contains children fragments but this fragment isn't
* visible right now. the platform will call the first child fragment in the view pager that
* it's visibility is true.
*
* @param isVisibleToUser
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && isViewPrepared() && isParentFragmentVisible())
//TODO: start your logic
}
/**
*
* @return true if the parent is fragment and visible or the parent isn't fragment
*/
boolean isParentFragmentVisible() {
return getParentFragment() == null || getParentFragment().getUserVisibleHint();
}
/**
*
* @return true if the view isn't null
*/
boolean isViewPrepared() {
return getView() != null;
}
}
/**
* Use this base fragment when you have fragment that has view pager and you want to handle
* when child fragments become actually visible to the user to start the logic.
*/
public abstract class BaseBootstrapHostViewPagerFragment extends BaseFragment {
/**
* Notify the current selected fragment inside view pager that it's setUserVisibleHint changed.
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isViewPrepared()) {
Fragment currentFragment = getChildFragmentManager().findFragmentByTag(
"android:switcher:" + getViewPagerId() + ":" + getViewPager().getCurrentItem());
if (currentFragment != null)
currentFragment.setUserVisibleHint(isVisibleToUser);
}
}
public abstract int getViewPagerId();
public abstract ViewPager getViewPager();
}
public FragmentC extend BaseBootstrapHostViewPagerFragment {....}
public Child1FragmentC extend BaseFragment {....}