【问题标题】:How to know if a Fragment is Visible?如何知道片段是否可见?
【发布时间】:2013-05-20 14:46:54
【问题描述】:

我正在使用支持库 v4,我的问题是,如何知道片段是否可见?以及如何更改片段中膨胀的布局的属性?提前致谢。

---编辑---

我正在使用带有 FragmentActivity 的 android 开发者教程中的片段

【问题讨论】:

标签: android android-fragments


【解决方案1】:

您应该能够做到以下几点:

MyFragmentClass test = (MyFragmentClass) getSupportFragmentManager().findFragmentByTag("testID");
if (test != null && test.isVisible()) {
     //DO STUFF
}
else {
    //Whatever
}

【讨论】:

  • 实际上是test != null && test.isVisible(),否则当test为空时会抛出NullPointerException
  • @Axxiss 谢谢,我忘了这一点,我在我的代码中做了两个不同的 if,但为了简单起见,这里只是对其进行了修改。想想看……我可能应该在我的代码中改变它……
  • 您只需if (MyFragmentClass.this.isVisible())即可。
  • 如果我们使用FragmentPagerAdapter在这个片段中添加更多片段呢?
  • 使用 tabLayout 将对与当前选项卡相邻的任何选项卡返回 true
【解决方案2】:

isVisible()isAdded() 在创建 Fragment 后立即返回 true,甚至实际上不可见。唯一有效的解决方案是:

if (isAdded() && isVisible() && getUserVisibleHint()) {
    // ... do your thing
}

这可以完成工作。期间。

注意: getUserVisibleHint() 现在已弃用。小心点。

【讨论】:

  • 我花了很多时间只是为了这个 getUserVisibleHint() THX
  • 是的,让我们把它带到顶部
  • isVisible 检查 isAdded 因此这里 isAdded 是多余的
  • isVisible 在 isAdded 之后。那么你能不能给出一个 isAdded 不起作用的场景,因为你提到了 isAdded 和 isVisible @Y.S.
  • getUserVisibleHint() 现在已弃用 - 有什么替代方案?
【解决方案3】:

如果您想知道何时使用正在查看您应该使用的片段

yourFragment.isResumed()

而不是

yourFragment.isVisible()

首先isVisible() 已经检查了isAdded(),因此无需同时调用两者。其次,这两者都不是意味着用户实际上正在查看您的片段。只有isResumed() 确保您的片段在用户面前,并且用户可以与它进行交互,如果这就是您要查找的内容。

【讨论】:

  • 漂亮的答案和解释,如果可以的话,+1 一百万次
  • 这不起作用。它让我对所有选项卡都是如此,即使只有一个正在使用且可见。
  • 它似乎不起作用。 isResumed 仍然返回“true”,即使片段在后堆栈中并且根本不可见。我在“onPrepareOptionsMenu”方法上检查了“isResumed”,并且在视图寻呼机中对子片段使用 getChildFragmentManager。
  • @leoOrion 我也有同样的情况
  • @KonstantinKonopko getUserVisibleHint() 会告诉你它是否对用户可见。即使片段在 backOfStack 中但对用户不可见,isVisible() 也会返回 true。
【解决方案4】:

你可以试试这个方法:

Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragment_container);

Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);

在这个 if 中,你检查 currentFragment 是否是 YourFragment 的实例

if (currentFragment instanceof YourFragment) {
     Log.v(TAG, "your Fragment is Visible");
}

【讨论】:

    【解决方案5】:

    您可以像这样覆盖 setMenuVisibility:

    @Override
    public void setMenuVisibility(final boolean visible) {
       if (visible) {
          //Do your stuff here
       }
    
       super.setMenuVisibility(visible);
    }
    

    【讨论】:

    • 非常感谢,奇怪的是这个名字的函数可以提供这样的功能,我一直在搜索这个问题,非常感谢。
    • 这对于使用 WhatsApp 等标签布局的人来说是正确的。谢谢你的回答。
    • 该方法在AndroidX中已弃用,需要使用哪种方法?
    • 感谢陌生人,拯救了我的一天!我在哪里可以捐给你? ?
    【解决方案6】:

    getUserVisibleHint() 只有当片段在视图上并且可见时才为真

    【讨论】:

    • 在我的情况下,每个片段返回 getUserVisibleHint() 是真的
    • 可能的情况是片段可能会被添加到具有纯色背景的后堆栈中。所以最近的片段隐藏了屏幕上的其他片段。
    • 在 API 29 中折旧
    【解决方案7】:

    需要注意的一点是,isVisible() 返回 当前 片段的可见状态。支持库中存在一个问题,如果您有嵌套片段,并且隐藏了父片段(因此隐藏了所有子片段),子片段仍然说它是可见的。

    isVisible() 是最终的,所以很遗憾不能覆盖。我的解决方法是创建一个所有片段都扩展的BaseFragment 类,然后创建一个像这样的方法:

    public boolean getIsVisible()
    {
        if (getParentFragment() != null && getParentFragment() instanceof BaseFragment)
        {
            return isVisible() && ((BaseFragment) getParentFragment()).getIsVisible();
        }
        else
        {
            return isVisible();
        }
    }
    

    我之所以选择isVisible() && ((BaseFragment) getParentFragment()).getIsVisible();,是因为如果隐藏了任何个父片段,我们希望返回 false。

    这似乎对我有用。

    【讨论】:

    • 谢谢!浪费了 2 个小时来挠头。
    • 如果父片段可见但正在检查的嵌套片段不可见怎么办?..我们如何检查这种情况?
    【解决方案8】:
    ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);
    
        if (articleFrag != null && articleFrag.isVisible()) {
    
            // Call a method in the ArticleFragment to update its content
            articleFrag.updateArticleView(position);
        }
    

    http://developer.android.com/training/basics/fragments/communicating.html

    【讨论】:

      【解决方案9】:

      如果你只有一个Fragment,试试这个

      if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
                          //TODO: Your Code Here
                      }
      
      

      【讨论】:

        【解决方案10】:

        在这里补充一些我经历过的信息:

        fragment.isVisible 仅在您使用 replaceFragment() 时才起作用 (true/false),否则如果您使用 addFragment()isVisible 总是返回 true,无论该片段是否位于其他片段的后面。

        【讨论】:

        • 任何解决方案来处理添加片段的情况?需要知道片段是否在 UI 中可见?
        【解决方案11】:

        以上解决方案都不适合我。 然而,以下内容就像一个魅力:-

        override fun setUserVisibleHint(isVisibleToUser: Boolean)
        

        【讨论】:

          【解决方案12】:

          万一您使用带有 ViewPager (TabLayout) 的 Fragment 布局,您可以通过 ViewPager.getCurrentItem() 方法轻松请求当前(前面的)片段。它会给你页面索引。

          从页面索引到片段[类]的映射应该很容易,因为您已经在 FragmentPagerAdapter 派生的适配器中进行了映射。

          int i = pager.getCurrentItem();
          

          您可以通过

          注册页面更改通知
          ViewPager pager = (ViewPager) findViewById(R.id.container);
          pager.addOnPageChangeListener(this);
          

          当然你必须实现接口ViewPager.OnPageChangeListener

          public class MainActivity 
              extends AppCompatActivity
              implements ViewPager.OnPageChangeListener
          {
              public void onPageSelected (int position)
              {
                  // we get notified here when user scrolls/switches Fragment in ViewPager -- so
                  // we know which one is in front.
                  Toast toast = Toast.makeText(this, "current page " + String.valueOf(position), Toast.LENGTH_LONG);
                  toast.show();
              }
          
              public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) {
              }
          
              public void onPageScrollStateChanged (int state) {
              }
          }
          

          我在这里的回答可能有点离题。但作为 Android 应用程序的新手,我正好面临这个问题,并没有在任何地方找到答案。所以制定了上述解决方案并将其发布在这里 - 也许有人觉得它有用。

          编辑:您可以将此方法与片段订阅的 LiveData 结合使用。此外,如果你给 Fragments 一个页面索引作为构造函数参数,你可以在你的 Fragment 类中创建一个简单的 amIvisible() 函数。

          在 MainActivity 中:

          private final MutableLiveData<Integer> current_page_ld = new MutableLiveData<>();
          public LiveData<Integer> getCurrentPageIdx() { return current_page_ld; }
          
          public void onPageSelected(int position) {
              current_page_ld.setValue(position);
          }
          
          public class MyPagerAdapter extends FragmentPagerAdapter
          {
              public Fragment getItem(int position) {
                  // getItem is called to instantiate the fragment for the given page: But only on first
                  // creation -- not on restore state !!!
                  // see: https://stackoverflow.com/a/35677363/3290848
                  switch (position) {
                      case 0:
                          return MyFragment.newInstance(0);
                      case 1:
                          return OtherFragment.newInstance(1);
                      case 2:
                          return XYFragment.newInstance(2);
                  }
                  return null;
              }
          }
          

          在片段中:

              public static MyFragment newInstance(int index) {
                  MyFragment fragment = new MyFragment();
                  Bundle args = new Bundle();
                  args.putInt("idx", index);
                  fragment.setArguments(args);
                  return fragment;
              }
          
              public void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  if (getArguments() != null) {
                      mPageIndex = getArguments().getInt(ARG_PARAM1);
                  }
                  ...
              }
              
              public void onAttach(Context context)
              {
                  super.onAttach(context);
                  MyActivity mActivity = (MyActivity)context;
          
                  mActivity.getCurrentPageIdx().observe(this, new Observer<Integer>() {
                      @Override
                      public void onChanged(Integer data) {
                          if (data == mPageIndex) {
                              // have focus
                          } else {
                              // not in front
                          }
                      }
                  });
              }
          

          【讨论】:

            【解决方案13】:

            getUserVisibleHint 现在已弃用,当另一个片段在它前面 added 时,我遇到了 isVisible 为真的问题。这会使用其视图检测片段在后台堆栈上的可见性。如果您的问题与后台堆栈上的其他片段有关,这可能会有所帮助。

            用于检测屏幕上是否正在显示视图的视图扩展:(另请参阅How can you tell if a View is visible on screen in Android?

            fun View.isVisibleOnScreen(): Boolean {
                if (!isShown) return false
                val actualPosition = Rect().also { getGlobalVisibleRect(it) }
                val screenWidth = Resources.getSystem().displayMetrics.widthPixels
                val screenHeight = Resources.getSystem().displayMetrics.heightPixels
                val screen = Rect(0, 0, screenWidth, screenHeight)
                return Rect.intersects(actualPosition, screen)
            }
            

            然后从片段中定义一个回栈监听器,观察栈顶的片段(最后添加的那个)

            fun Fragment.setOnFragmentStackVisibilityListener(onVisible: () -> Unit) {
                val renderDelayMillis = 300L
                parentFragmentManager.addOnBackStackChangedListener {
                    Handler(Looper.getMainLooper()).postDelayed({
                        if (isAdded) {
                            val topStackFragment = parentFragmentManager.fragments[parentFragmentManager.fragments.size - 1]
                            if (topStackFragment.view == view && isVisible && view!!.isVisibleOnScreen()) {
                                onVisible.invoke()
                            }
                        }
                    }, renderDelayMillis)
                }
            }
            

            在视图准备好之前调用返回堆栈侦听器,因此需要任意小的延迟。当视图可见时调用 lambda。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-07-31
              • 1970-01-01
              • 2015-03-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多