问题:ViewPager中的Fragment onResume()在片段实际可见之前被激发。

例如,我有2个带有ViewPager和FragmentPagerAdapter的片段。第二个片段仅对授权用户可用,我需要在片段可见时要求用户登录(使用警告对话框)。

但是,当第一个片段可见时,ViewPager创建第二个片段,以便缓存第二个碎片,并在用户开始滑动时使其可见。

因此,onResume()事件在第二个片段可见之前很久就被激发了。这就是为什么我试图找到一个事件,当第二个片段变得可见时,该事件会触发,以便在适当的时候显示对话框。

如何做到这一点?


当前回答

我用了这个,它奏效了!

mContext.getWindow().getDecorView().isShown() //boolean

其他回答

可能很晚了。这对我很有用。我稍微更新了@Gobar和@kris解决方案的代码。我们必须更新PagerAdapter中的代码。

每当选项卡可见并返回其位置时,都会调用setPrimaryItem。如果位置相同,意味着我们不动。如果位置已更改且当前位置不是我们单击的选项卡设置为-1。

private int mCurrentPosition = -1;

@Override
public void setPrimaryItem(@NotNull ViewGroup container, int position, @NotNull Object object) {
    // This is what calls setMenuVisibility() on the fragments
    super.setPrimaryItem(container, position, object);
    if (position == mCurrentPosition) {
        return;
    }
    if (object instanceof YourFragment) {
        YourFragment fragment = (YourFragment) object;
        if (fragment.isResumed()) {
            mCurrentPosition = position;
            fragment.doYourWork();//Update your function
        }
    } else {
        mCurrentPosition = -1;
    }
}

我支持带有子片段的SectionsPagerAdapter,所以在经历了很多头疼之后,我终于得到了基于本主题解决方案的工作版本:

public abstract class BaseFragment extends Fragment {

    private boolean visible;
    private boolean visibilityHintChanged;

    /**
     * Called when the visibility of the fragment changed
     */
    protected void onVisibilityChanged(View view, boolean visible) {

    }

    private void triggerVisibilityChangedIfNeeded(boolean visible) {
        if (this.visible == visible || getActivity() == null || getView() == null) {
            return;
        }
        this.visible = visible;
        onVisibilityChanged(getView(), visible);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (!visibilityHintChanged) {
            setUserVisibleHint(false);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (getUserVisibleHint() && !isHidden()) {
            triggerVisibilityChangedIfNeeded(true);
        }
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        triggerVisibilityChangedIfNeeded(!hidden);
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        visibilityHintChanged = true;
        if (isVisibleToUser && isResumed() && !isHidden()) {
            triggerVisibilityChangedIfNeeded(true);
        } else if (!isVisibleToUser) {
            triggerVisibilityChangedIfNeeded(false);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        triggerVisibilityChangedIfNeeded(false);
    }

    @Override
    public void onStop() {
        super.onStop();
        triggerVisibilityChangedIfNeeded(false);
    }

    protected boolean isReallyVisible() {
        return visible;
    }
}

在Kotlin

override fun onHiddenChanged(hidden: Boolean) {
    super.onHiddenChanged(hidden)

    // Your code goes here..
}

更新:Android支持库(rev 11)最终修复了用户可见提示问题,现在如果您将支持库用于片段,那么您可以安全地使用getUserVisibleHint()或重写setUserVisibleHint()来捕获gorn的答案所描述的更改。

UPDATE 1 getUserVisibleHint()有一个小问题。默认情况下,该值为true。

// Hint provided by the app that this fragment is currently visible to the user.
boolean mUserVisibleHint = true;

因此,在调用setUserVisibleHint()之前尝试使用它可能会出现问题。作为解决方法,您可以像这样在onCreate方法中设置值。

public void onCreate(@Nullable Bundle savedInstanceState) {
    setUserVisibleHint(false);

过时的答案:

在大多数使用情况下,ViewPager一次只显示一个页面,但如果您在Android支持库r11之前的版本中使用FragmentStatePagerAdapter,则预缓存的片段也会处于“可见”状态(实际上不可见)。

我覆盖:

public class MyFragment extends Fragment {
    @Override
    public void setMenuVisibility(final boolean visible) {
        super.setMenuVisibility(visible);
        if (visible) {
            // ...
        }
    }
   // ...
}

为了捕获片段的焦点状态,我认为这是最适合的“可见性”状态,因为ViewPager中只有一个片段可以将其菜单项与父活动的项放在一起。

如何确定片段何时在ViewPager中可见

您可以通过覆盖片段中的setUserVisibleHint来执行以下操作:

public class MyFragment extends Fragment {
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
        }
        else {
        }
    }
}