【问题标题】:ViewPager's Fragment's nested child fragment has setUserVisibleHint trueViewPager 的 Fragment 的嵌套子 Fragment 有 setUserVisibleHint true
【发布时间】:2018-02-01 17:48:18
【问题描述】:

我有一个 ViewPager 有 4 个片段(a、b、c、d),c 和 d 都有 ViewPagers,本质上是嵌套的视图寻呼机。我附上了一张图片来说明我的布局。因此,当我选择片段 B 时,片段 C 中的 setUserVisibleHint(boolean)truesetUserVisibleHint(boolean)false,这是预期的行为。但是,即使 Fragment C 中的 setUserVisibleHint(boolean)false,但 Fragment C 中第一个 Fragment 中的 setUserVisibleHint(boolean) ViewPagertrue

我认为这不是预期的行为。有人可以告诉这里可能发生了什么吗?我将不胜感激任何意见。

【问题讨论】:

  • 也许你的意思是setUserVisibleHint(boolean)而不是setUserVisibility
  • @azizbekian 是的,抱歉,我已经更新了

标签: android android-fragments android-viewpager fragmentpageradapter setuservisiblehint


【解决方案1】:

来自setUserVisibleHint(boolean)的文档:

向系统设置有关此片段的 UI 当前是否对用户可见的提示。此提示默认为 true,并且在片段实例状态保存和恢复期间保持不变。

应用可以将设置为 false,以指示 Fragment 的 UI 被滚动到不可见或不直接对用户可见。系统可以使用它来确定片段生命周期更新或加载程序排序行为等操作的优先级。

可以从文档中概述:

  • 此值默认为true
  • 该值不是由框架自动设置。它是“应用程序”,可能会或可能不会设置此标志。

如果您查看setUserVisibleHint(boolean) 的用法,您会看到以下列表:

因此,只有PagerAdapter 实现调用该方法。 正如您所概述的,PagerAdapter 为它拥有的所有片段正确设置了该标志。

PagerAdapter 对子片段不明智,片段 C 有。 PagerAdapter 有责任为片段 C 的子片段设置该标志。手动设置该布尔值是“应用程序”(在本例中为您)的责任。

【讨论】:

  • 我认为片段 c 有一个 PagerAdapter,它应该处理该 PagerAdapter 中的片段标志?
  • 当我导航到片段 b 并手动设置布尔值 userVisibleHint = false 它设置正确,但是 setUserVisibleHint(boolean) 被击中 3 次,第一次到时间 isVisibleToUserfalse,第三次它恢复为true 在它真正可见之前它永远不会是真的,所以我不确定a。为什么它被称为setUserVisibleHint(boolean) 被调用了 3 次,为什么它被设置为 true
  • 谁能告诉我一个确定的方法来识别视图寻呼机片段中的视图寻呼机片段何时变得可见。我已经尝试过onPageSelected() 我已经尝试过setUserVisibleHint(boolean) 并且我已经尝试过setPrimaryItem(container: ViewGroup, position: Int, object: Any) 这变得非常令人沮丧,因为我需要确定片段何时对用户可见以跟踪使用情况。跨度>
  • this 答案。
【解决方案2】:

您应该检查父级是否为片段且可见或不是片段,然后开始您的逻辑。

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 {....}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多