如何测试一个Fragment视图是否对用户可见?

73

我有一个ViewPager,每个页面都是一个Fragment视图。我想测试一个Fragment是否在可见区域内。Fragment.isVisible只会测试:

  • 该Fragment已附加到一个Activity上
  • 该Fragment已设置为可见
  • 该Fragment已添加到一个View中

ViewPager默认会创建3个Fragment,并且它们三个都符合上述条件,但实际上只有一个Fragment对用户(人类的眼睛)可见。


请发布您的代码以获取更好的帮助。 - Raj
4
我现在也非常想知道那个答案。 - Manfred Moser
10个回答

66

这是我用来确定片段可见性的方法。

private static boolean m_iAmVisible;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) { 
    super.setUserVisibleHint(isVisibleToUser);
    m_iAmVisible = isVisibleToUser;

    if (m_iAmVisible) { 
        Log.d(localTAG, "this fragment is now visible");
    } else {  
        Log.d(localTAG, "this fragment is now invisible");
    }
}

根据文档,这并不起作用:“向系统设置一个提示,指示此片段的用户界面当前是否对用户可见。此提示默认为true,并在片段实例状态保存和恢复时保持不变。” - Edison
1
好的解决方案(+1),但代码可以简化:public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); m_iAmVisible = false; //默认为不可见 if (isVisibleToUser) { m_iAmVisible = true; } } - PeteH
2
公共的无返回值方法 setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); m_iAmVisible = isVisibleToUser; } - Kasas
30
更简单地说,getUserVisibleHint() - Leonardo Pinto
1
这非常有帮助,谢谢! - Lazar Kukolj

19

你说的没错,有更好的方法可以做到这一点!

请查看在线的FragmentPagerAdapter javadoc,你会发现有一个方法setPrimaryItem(ViewGroup container, int position, Object object):void正好能满足你的需求。

从javadoc中可以得知

public void setPrimaryItem (ViewGroup container, int position, Object object)

被调用以通知适配器当前哪个项目被认为是“主要项目”,也就是显示给用户作为当前页面的项目。

参数 container: 将要移除页面的包含视图。position:现在的页面位置是主要页面。object:由instantiateItem(View,int)返回的相同对象。

关于滚动状态的说明

如果你实现了这个方法并开始调试以了解它何时被调用,你很快就会发现在准备片段和用户滑动时它会被多次触发。

因此,最好还是附加一个ViewPager.OnPageChangeListener并仅在viewpager的滚动状态再次变为SCOLL_STATE_IDLE时执行必要的操作。


1
如果一个人扩展了Application类并且需要测试特定的UI是否正在显示,那么这种方法非常有效。我最终使用了几个布尔值来测试应用程序是否处于后台,并且特定的片段是否正在显示。 - Someone Somewhere

9

为了我的目的,我使用 ViewPager.OnPageChangeListener.onPageSelected() 结合 Fragment.onActivityCreated() 来执行片段可见时的操作。 Fragment.getUserVisibleHint() 也很有帮助。


3

我正在使用“setMenuVisibility”方法来解决这个问题。由于每个片段都可以拥有操作栏项目,因此这是您可以确定哪个片段当前对用户可见的部分。

@Override
public void setMenuVisibility(final boolean visible) {
    super.setMenuVisibility(visible);
    if (!visible) {
        //not visible anymore
    }else{
        yay visible to the user
    }
}

3
使用 getView().isShown() 来判断 Fragment 是否可见有什么问题吗?

你测试过你的想法吗?我认为这篇帖子指出了相同的想法。 - David S.
是的。正如链接帖子中建议的那样,它对我有效。 - awy

3
isVisible() 

即使片段位于活动后面,仍然可以返回True。

我正在使用以下内容:

if (getView() != null && getView().isShown()) {
//your code here
}

1
根据这里的内容,isShown类似于getVisibility(),因此如果一个视图虽然是VISIBLE但被另一个活动覆盖时,它仍然可以返回true。 - Mysterious_android

2
如果您知道每个片段所附加的“页面”,则可以使用ViewPager.getCurrentItem()来确定哪个片段是“可见”的。

4
这是我现在正在做的事情。我只是在思考是否有其他方式。谢谢。 - David S.

0

在API 27中已被弃用 - Yasiru Nayanajith

0
在我的情况下,当片段对用户可见时,我需要对第一个片段进行一些工作。
 @Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);


    if(viewPager.getAdapter() instanceof YourPager)
    {
        Fragment fragemnt=((YourPager)viewPager.getAdapter()).getFragment(0); //getFragment(int index) custom method
        if( fragemnt instanceof YourFragment)
        {
            ((YourFragment)fragemnt).methodWhochShouldBeCalledAfterUIVisible();
        }
    }
}

0

setUserVisibleHint可能不会被调用,onHiddenChanged也不一定每次在其他片段关闭时都会被调用。因此,您可以依赖于onResume(和onPause),但通常它会被过度调用(例如当您打开设备屏幕时)。在某些情况下,它也不会被调用,您应该在主活动中管理当前片段并编写:

if (currentFragment != null) {
    currentFragment.onResume();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接