85

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

- -编辑 - -

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

4

13 回答 13

115

您应该能够执行以下操作:

MyFragmentClass test = (MyFragmentClass) getSupportFragmentManager().findFragmentByTag("testID");
if (test != null && test.isVisible()) {
     //DO STUFF
}
else {
    //Whatever
}
于 2013-05-20T14:52:34.937 回答
54

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

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

这可以完成工作。时期。

注意:getUserVisibleHint() 现已弃用。当心。

于 2016-09-02T13:04:17.847 回答
39

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

yourFragment.isResumed()

代替

yourFragment.isVisible()

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

于 2017-01-25T21:41:29.637 回答
17

你可以这样尝试:

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");
}
于 2016-04-15T12:02:10.953 回答
14

您可以像这样覆盖 setMenuVisibility:

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

   super.setMenuVisibility(visible);
}
于 2013-05-20T16:24:28.587 回答
10

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

于 2016-02-19T12:21:42.593 回答
8

需要注意的一件事是,它返回当前片段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 。

这似乎对我有用。

于 2014-06-11T13:57:01.827 回答
3
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

于 2013-05-20T14:52:22.377 回答
1

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

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

于 2020-09-18T20:06:23.517 回答
0

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

override fun setUserVisibleHint(isVisibleToUser: Boolean)
于 2020-06-15T15:10:13.233 回答
0

在这里添加一些我经历过的信息:

fragment.isVisible仅当您使用 ( true/false) 时,replaceFragment()如果您使用addFragment(),则isVisible始终返回true该片段是否位于其他片段的后面。

于 2020-12-18T16:07:57.627 回答
0

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

从页面索引到 fragment[class] 的映射应该很容易,因为您已经在 FragmentPagerAdapter 派生的 Adapter 中进行了映射。

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 提供页面索引作为构造函数参数,则可以在片段类中创建一个简单的 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
                }
            }
        });
    }
于 2021-02-11T22:28:28.210 回答
0

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

用于检测屏幕上是否正在显示视图的视图扩展:(另请参阅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)
}

然后从fragment中定义了一个back stack listener,观察栈顶的fragment(最后添加的那个)

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。

于 2021-08-26T01:00:30.907 回答