添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

如何确定Fragment在ViewPager中变得可见?

818 人关注

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

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

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

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

如何才能做到这一点呢?

5 个评论
"我有两个带有ViewPager和FragmentPagerAdapter的片段。第二个片段可以只对授权用户开放,当片段可见时,我应该要求用户登录(警报对话框)。"-- IMHO,这是糟糕的用户体验。因为用户水平滑动而弹出一个对话框会导致我在Play Store上给你一个一星的评价。
在TextView中用 "登录 "按钮显示信息是否更好?你对这种情况有什么解决办法?
"如果不显示,就没有必要加载数据。"-- 那么你就不应该把它放在 ViewPager 中。在一个两页的分页器中,无论你喜欢与否,两个页面都会被立即加载。替换代码0】的用户体验应该是,内容在滑动时立即出现,而不是在一段时间后才出现。这就是为什么 ViewPager 会在可见内容之前初始化一个页面,以帮助确保这种用户体验。
似乎ViewPager不够灵活,它不允许关闭缓存,因为最小的setOffscreenPageLimit是1。 stackoverflow.com/questions/10073214/... .我看不出有什么原因,预期的行为(在强制缓存的情况下)是创建片段,但在片段变得可见时启动片段的onResume()。
有点晚了,但对于面临同样问题的人,你可以试试 碎片查看器(FragmentViewPager) 库(我是作者),它处理了这个问题并提供了一些额外的功能。要想获得样本,请查看项目的GitHub页面或这个 堆栈溢出的答案 .
android
android-fragments
android-viewpager
4ntoine
4ntoine
发布于 2012-04-05
27 个回答
gorn
gorn
发布于 2013-01-12
已采纳
0 人赞同

如何确定Fragment在ViewPager中变得可见?

你可以通过在你的 Fragment 中覆盖 setUserVisibleHint 来完成以下工作。

public class MyFragment extends Fragment {
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
        else {
    
感谢今天的安卓支持库更新(rev 11),用户可见提示的问题终于得到了解决。现在可以安全地使用ViewPager的用户可见提示了。
我发现setUserVisibleHint方法在调用onCreateView之前就被调用了,这使得我们很难跟踪任何初始化。
@AndroidDev 如果你想在提示为真时运行一些代码,但需要视图树已经初始化,只需将该代码块包裹在 isResumed() 中,以避免出现NPE。这对我来说是很好的。
对于SDK应该默认提供的东西,竟然有这么多不同的黑客,这实在是太可笑了。
S.R
setUserVisibleHint is now 废弃的
Oasis Feng
Oasis Feng
发布于 2013-01-12
0 人赞同

更新 :安卓支持库(11版)最后 fixed the user visible hint issue , 现在如果你使用支持库的片段,那么你可以安全地使用 getUserVisibleHint() 或覆盖 setUserVisibleHint() 来捕获gorn答案中描述的变化。

更新 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 Support Library pre-r11中使用FragmentStatePagerAdapter,预先缓存的片段也会被放到 "可见 "状态(实际上是不可见)。

I override :

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

为了捕捉片段的焦点状态,我认为这是你所说的 "可见性 "的最合适的状态,因为ViewPager中只有一个片段可以实际地将其菜单项和父活动的项放在一起。

请注意使用getActivity(),在第一次启动时它将是空的。
请注意,setUserVisibleHint()在FragmentPagerAdapter中一直都能正常工作。
这个解决方案(还有gorn的)有点滞后。在viewpager被快速和多次滑动的情况下,这个方法将被延迟调用(当片段不再可见/不可见)。
当调用 onCreateOptionsMenu 时,我得到 true 的getUserVisibleHint(),而当调用 setUserVisibleHint 时,似乎菜单还没有被创建。最终我得到了两个选项Menu's added,而我只想得到可见片段的菜单。在这方面有什么建议吗?
S.R
setUserVisibleHint is now 废弃的
craigrs84
craigrs84
发布于 2013-01-12
0 人赞同

这似乎恢复了你所期望的正常 onResume() 行为。 它在按下主键离开应用,然后重新进入应用时发挥得很好。 替换代码0】不会被连续调用两次。

@Override
public void setUserVisibleHint(boolean visible)
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
        //Only manually call onResume if fragment is already visible
        //Otherwise allow natural fragment lifecycle to call onResume
        onResume();
@Override
public void onResume()
    super.onResume();
    if (!getUserVisibleHint())
        return;
    //INSERT CUSTOM CODE HERE
    
Alex
这正是我在寻找的东西。解决了 setUserVisibleHint onCreateView 之前被调用的问题,以及 setUserVisibleHint 在应用程序进入后台和前台时不会被调用。真棒!谢谢谢谢你!
我认为自己调用onResume是一个相当糟糕的主意,但除此之外,你需要回答这个帖子的问题的所有内容都在setUserVisibleHint函数中 !
我宁愿实现一个普通的 onVisibleToUser() 方法,让它从 onResume() setUserVisibleHint(boolean) 中被调用,而不是自己调用 onResume() 并干扰生命周期的回调。 否则,我认为这种方法很好,谢谢!
是的,我同意上面的评论。一般来说,尽量避免从你的类中的公共方法调用公共方法。做一个私有方法并从两个公共方法中调用它。
setUserVisibleHint已被弃用!
Ostkontentitan
Ostkontentitan
发布于 2013-01-12
0 人赞同

下面是另一种使用 onPageChangeListener 的方法。

  ViewPager pager = (ViewPager) findByViewId(R.id.viewpager);
  FragmentPagerAdapter adapter = new FragmentPageAdapter(getFragmentManager);
  pager.setAdapter(adapter);
  pager.setOnPageChangeListener(new OnPageChangeListener() {
  public void onPageSelected(int pageNumber) {
    // Just define a callback method in your fragment and call it like this! 
    adapter.getItem(pageNumber).imVisible();
  public void onPageScrolled(int arg0, float arg1, int arg2) {
    // TODO Auto-generated method stub
  public void onPageScrollStateChanged(int arg0) {
    // TODO Auto-generated method stub
    
这个方案效果很好,谢谢。 对于那些使用(v4)片段支持包为旧平台进行构建的人来说,这应该是推荐的解决方案。
值得注意的是,如果你使用一个FragmentStatePagerAdapter并在getItem()上实例化一个新的Fragment实例,这可能不会给你带来预期的结果,因为你只是在新的片段上设置状态,而不是在viewpager得到的那个片段上。
如果你想在片段变得可见时执行某些操作,这个解决方案是不错的。它不保留片段的可见状态(意思是,它不知道片段何时不可见)。
我也有同样的问题,请帮助我解决这个问题。我的帖子 : stackoverflow.com/questions/23115283/...
@AsafK 如果你在标签里有 ViewPager ,一次只能看到一个片段,对吗?所以我们不能假设除了 onPageSelected 被调用的那一个,其他的都是隐藏的吗?
Jemshit Iskenderov
Jemshit Iskenderov
发布于 2013-01-12
0 人赞同

替换代码0】有时会被调用 before 替换代码1】,有时会在这之后造成麻烦。

为了克服这个问题,你需要在 setUserVisibleHint() 方法中也检查 isResumed() 。但在这种情况下,我发现 setUserVisibleHint() 被调用了 only 如果Fragment被恢复并且可见,而不是在创建时。

因此,如果你想在Fragment为 visible 时更新一些东西,把你的更新函数同时放在 onCreate() setUserVisibleHint() 中。

@Override
public View onCreateView(...){
    myUIUpdate();
@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){
        myUIUpdate();

更新。但我还是意识到myUIUpdate()有时会被调用两次,原因是,如果你有3个标签,而这个代码在第2个标签上,当你第一次打开第1个标签时,第2个标签也被创建,即使它不可见,myUIUpdate()也被调用。然后当你滑动到第2个标签时,myUIUpdate()if (visible && isResumed())被调用,结果,myUIUpdate()可能在一秒钟内被调用两次。

The other problem!visiblesetUserVisibleHint中被调用,1)当你离开片段屏幕时;2)在它被创建之前,当你第一次切换到片段屏幕时。

Solution:

private boolean fragmentResume=false;
private boolean fragmentVisible=false;
private boolean fragmentOnCreated=false;
@Override
public View onCreateView(...){
    //Initialize variables
    if (!fragmentResume && fragmentVisible){   //only when first time fragment is created
        myUIUpdate();
@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){   // only at fragment screen is resumed
        fragmentResume=true;
        fragmentVisible=false;
        fragmentOnCreated=true;
        myUIUpdate();
    }else  if (visible){        // only at fragment onCreated
        fragmentResume=false;
        fragmentVisible=true;
        fragmentOnCreated=true;
    else if(!visible && fragmentOnCreated){// only when you go out of fragment screen
        fragmentVisible=false;
        fragmentResume=false;

解释一下。

fragmentResumefragmentVisible。确保onCreateView()中的myUIUpdate()只在片段被创建并可见时被调用,而不是在恢复时被调用。这也解决了当你在第1个标签时,第2个标签被创建,即使它不可见的问题。这解决了这个问题,并在onCreate时检查片段屏幕是否可见。

fragmentOnCreated。确保片段不可见,并且在你第一次创建片段时不被调用。所以现在这个if子句只在你刷出片段的时候被调用。

你可以把所有这些代码放在BaseFragment代码中like this和重写方法。

你的解决方案工作得很好,除了一种情况,当片段被正常打开,然后你点击一些按钮,用另一个片段替换它,然后点击返回,从后台弹出新的片段,这种情况下 setUserVisibleHint 没有被调用。而在 onCreateView 方法中, fragmentVisible false !所以片段显示为空。
lukjar
lukjar
发布于 2013-01-12
0 人赞同

ViewPager2 ViewPager 中,从版本 androidx.fragment:fragment:1.1.0 开始,你可以直接使用 onPause onResume 回调来确定当前哪个片段对用户是可见的。当片段变得可见时, onResume 回调被调用,当它停止可见时, onPause 被调用。

在ViewPager2的情况下,它是默认的行为,但同样的行为可以很容易地启用旧的 ViewPager

为了在第一个ViewPager中启用这一行为,你必须将 FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT 参数作为 FragmentPagerAdapter 构造函数的第二个参数。

FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

注意。带有一个参数的setUserVisibleHint()方法和FragmentPagerAdapter构造函数在android jetpack的新版本Fragment中已经废弃。

谢谢你的好办法。我一直在寻找这个办法。伟大的工作
对于ViewPager2,选项BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT不是默认行为,你需要手动设置。当设置这个选项时,你的解决方案对我有用。谢谢。
从2020年APR开始,这就是最新的解决方案,而且运作得很好。
@4ntoine 请考虑接受这个答案为正确答案,因为从目前来看,这个答案是正确的,而大多数答案都在使用被废弃的setUserVisibleHint方法。
我认为它与FragmentStateAdapter也能很好地工作。这对任何安卓开发者来说都是一个巨大的安慰。感谢google在这么长时间后解决了这个问题。
Linh
Linh
发布于 2013-01-12
0 人赞同

ViewPager2 + FragmentStateAdapter + onResume() (in Fragment) solve the problem

Old Answer (deprecated)

要检测 Fragment 中的 ViewPager 可见,我很确定 only using setUserVisibleHint is not enough.
这是我检查一个片段是否可见或不可见的方案。首先,当启动viewpager时,在页面之间切换,转到另一个活动/片段/背景/前景`。

public class BaseFragmentHelpLoadDataWhenVisible extends Fragment {
    protected boolean mIsVisibleToUser; // you can see this variable may absolutely <=> getUserVisibleHint() but it not. Currently, after many test I find that
     * This method will be called when viewpager creates fragment and when we go to this fragment background or another activity or fragment
     * NOT called when we switch between each page in ViewPager
    @Override
    public void onStart() {
        super.onStart();
        if (mIsVisibleToUser) {
            onVisible();
    @Override
    public void onStop() {
        super.onStop();
        if (mIsVisibleToUser) {
            onInVisible();
     * This method will called at first time viewpager created and when we switch between each page
     * NOT called when we go to background or another activity (fragment) when we go back
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        mIsVisibleToUser = isVisibleToUser;
        if (isResumed()) { // fragment have created
            if (mIsVisibleToUser) {
                onVisible();
            } else {
                onInVisible();
    public void onVisible() {
        Toast.makeText(getActivity(), TAG + "visible", Toast.LENGTH_SHORT).show();
    public void onInVisible() {
        Toast.makeText(getActivity(), TAG + "invisible", Toast.LENGTH_SHORT).show();
你可以仔细检查下面的logcat,然后我想你可能会知道为什么这个解决方案会有效

第一次发射

Fragment1: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment2: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment3: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment1: setUserVisibleHint: isVisibleToUser=true isResumed=false // AT THIS TIME isVisibleToUser=true but fragment still not created. If you do something with View here, you will receive exception
Fragment1: onCreateView
Fragment1: onStart mIsVisibleToUser=true
Fragment2: onCreateView
Fragment3: onCreateView
Fragment2: onStart mIsVisibleToUser=false
Fragment3: onStart mIsVisibleToUser=false

转到第2页

Fragment1: setUserVisibleHint: isVisibleToUser=false isResumed=true
Fragment2: setUserVisibleHint: isVisibleToUser=true isResumed=true

转到第3页

Fragment2: setUserVisibleHint: isVisibleToUser=false isResumed=true
Fragment3: setUserVisibleHint: isVisibleToUser=true isResumed=true

转到背景。

Fragment1: onStop mIsVisibleToUser=false
Fragment2: onStop mIsVisibleToUser=false
Fragment3: onStop mIsVisibleToUser=true

Go to foreground

Fragment1: onStart mIsVisibleToUser=false
Fragment2: onStart mIsVisibleToUser=false
Fragment3: onStart mIsVisibleToUser=true

DEMO project here

Hope it help

Shihab Uddin
当一个片段有另一个同样由片段组成的view pager时,它不起作用。
Linh
对不起,我现在不能发布答案,因为我没有足够的时间,如果可能的话,请参考我的git关于你的问题,在这里 github.com/PhanVanLinh/AndroidViewPagerSkeleton/tree/master . SubChildContainerFragment 用于检测 a fragment has another view pager which also consists fragment 。你可以将 SubChildContainerFragment ChildContainerFragment 混合为一个类别。希望这对你有帮助。我稍后将发布完整的答案
w3hacker
w3hacker
发布于 2013-01-12
0 人赞同
package com.example.com.ui.fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.com.R;
public class SubscribeFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_subscribe, container, false);
        return view;
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // called here
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    
RajV
这应该是公认的答案。也能与android.app.Fragment一起工作,这是一个巨大的收获。
setUserVisibleHint Deprecated
kris larson
kris larson
发布于 2013-01-12
0 人赞同

FragmentPagerAdapter 子类中覆盖 setPrimaryItem() 。我使用这种方法,而且效果很好。

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    // This is what calls setMenuVisibility() on the fragments
    super.setPrimaryItem(container, position, object);
    if (object instanceof MyWhizBangFragment) {
        MyWhizBangFragment fragment = (MyWhizBangFragment) object;
        fragment.doTheThingYouNeedToDoOnBecomingVisible();
    
Gober
这几乎成功了,但有NPE和被多次调用的问题。下面发布了一个替代方案。
@Gober在第一次保存Object对象,并检查和忽略对同一Object对象的后续调用,就像FragmentStateAdapter在setPrimaryItem()方法中做的那样。
dan
dan
发布于 2013-01-12
0 人赞同

Override Fragment.onHiddenChanged() 对于这一点。

public void onHiddenChanged(boolean hidden)

当隐藏状态(如由 isHidden() )的片段已经改变。片段开始时是不隐藏的;每当片段的状态从此改变时,这将被调用。

【替换代码3- boolean 。如果该片段现在被隐藏,则为真,如果不可见,则为假。

这个方法现在已经被废弃了,不能再使用了。
Cel
@bluewhile 你在哪里看到它被废弃了? developer.android.com/reference/android/app/...
我刚刚成功地使用了这个方法,而且文档中似乎没有指出它已被废弃。
dan
@bluewhile,在4.1(api 16)中,它还没有被废弃。
我正在使用API级别19,可以确认,虽然这不是废弃的,但它并不像宣传的那样工作。例如,当片段被另一个片段隐藏时,onHiddenChanged不被调用。
Top-Master
Top-Master
发布于 2013-01-12
0 人赞同

只有这个对我有用!!而且 setUserVisibleHint(...) 现在已经被废弃了(我在最后附上了文档),这意味着其他大部分答案都被废弃了;-)

public class FragmentFirewall extends Fragment {
     * Required cause "setMenuVisibility(...)" is not guaranteed to be
     * called after "onResume()" and/or "onCreateView(...)" method.
    protected void didVisibilityChange() {
        Activity activity = getActivity();
        if (isResumed() && isMenuVisible()) {
            // Once resumed and menu is visible, at last
            // our Fragment is really visible to user.
    @Override
    public void onResume() {
        super.onResume();
        didVisibilityChange();
    @Override
    public void setMenuVisibility(boolean visible) {
        super.setMenuVisibility(visible);
        didVisibilityChange();

经测试,也能与NaviagationDrawer一起使用。 在那里isMenuVisible()将总是返回true(而onResume()似乎已经足够了,但我们也想支持ViewPager)。

setUserVisibleHint已被弃用。如果重写这个方法,在传递true时实现的行为应该移到Fragment.onResume()中,而在传递false时实现的行为应该移到Fragment.onPause()

Rahul
Rahul
发布于 2013-01-12
0 人赞同

setUserVisibleHint(boolean visible) is now 废弃的 So this is the correct solution

FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

In 查看页面2查看页面 from version androidx.fragment:fragment:1.1.0 you can just use onPause()onResume() to determine which fragment is currently visible for the user. onResume() is called when the fragment became visible和onPause when it stops to be visible.

To enable this behavior in the first 查看页面 you have to pass FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT parameter as the second argument of the FragmentPagerAdapter constructor.

你是救世主,这是2021年的最佳答案,因为上述所有答案都是贬值的。
ismailarilik
ismailarilik
发布于 2013-01-12
0 人赞同

我发现 onCreateOptionsMenu onPrepareOptionsMenu 方法只在片段的情况下被调用。 真的 可见。我没有找到任何像这样的方法,我也试过 OnPageChangeListener ,但它在某些情况下不起作用,例如,我需要在 onCreate 方法中初始化一个变量。

因此,这两种方法可以作为一种变通方法来解决这个问题,特别是对于小而短的工作。

我认为,这是更好的解决方案,但不是最好的。我将使用这个方案,但同时也在等待更好的解决方案。

Gober
Gober
发布于 2013-01-12
0 人赞同

另一种解决方案 发表于此 在pageradapter中重写setPrimaryItem by kris larson 几乎对我有用。但这个方法在每个设置中都被多次调用。我还得到了 NPE 在片段中的视图等,因为在这个方法被调用的前几次,这还没有准备好。在做了以下改动后,这对我来说是有效的。

private int mCurrentPosition = -1;
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    super.setPrimaryItem(container, position, object);
    if (position == mCurrentPosition) {
        return;
    if (object instanceof MyWhizBangFragment) {
        MyWhizBangFragment fragment = (MyWhizBangFragment) object;
        if (fragment.isResumed()) {
            mCurrentPosition = position;
            fragment.doTheThingYouNeedToDoOnBecomingVisible();
    
不工作。它只调用了一次。如果再次返回到同一页面,mCurrentPosition和位置是相等的。
Afzaal Iftikhar
Afzaal Iftikhar
发布于 2013-01-12
0 人赞同

在片段中加入以下代码

@Override
public void setMenuVisibility(final boolean visible) 
    super.setMenuVisibility(visible);
    if (visible && isResumed()) 
    
这只适用于ViewPagerFragments。对正常活动中的片段不适用。
0 人赞同

我在使用 FragmentStatePagerAdapters 和3个标签时遇到了同样的问题。我不得不在点击第一个标签时显示一个Dilaog,而在点击其他标签时隐藏它。

单独覆盖 setUserVisibleHint() 并不能帮助找到当前可见的片段。

When clicking from 3rd tab -----> 1st tab. It triggered twice for 2nd fragment and for 1st fragment. I combined it with isResumed() method.

    @Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    isVisible = isVisibleToUser;
    // Make sure that fragment is currently visible
    if (!isVisible && isResumed()) {
        // Call code when Fragment not visible
    } else if (isVisible && isResumed()) {
       // Call code when Fragment becomes visible.
    
Pin
Pin
发布于 2013-01-12
0 人赞同

我们有一个MVP的特殊情况,片段需要通知presenter,视图已经变得可见,presenter是由Dagger在 fragment.onAttach() 中注入的。

setUserVisibleHint() 是不够的,我们已经检测到3种不同的情况需要解决(提到 onAttach() 是为了让你知道主讲人何时有空)。

  • 片段刚刚被创建。系统进行以下调用。

    setUserVisibleHint() // before fragment's lifecycle calls, so presenter is null
    onAttach()
    onResume()
    
  • 片段已经创建,主页按钮被按下。当把应用程序恢复到前台时,这个被调用。

    onResume()
    
  • 方向改变。

    onAttach() // presenter available
    onResume()
    setUserVisibleHint()
    

    我们只想让可见性提示到达演示者一次,所以我们是这样做的。

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_list, container, false);
        setHasOptionsMenu(true);
        if (savedInstanceState != null) {
            lastOrientation = savedInstanceState.getInt(STATE_LAST_ORIENTATION,
                  getResources().getConfiguration().orientation);
        } else {
            lastOrientation = getResources().getConfiguration().orientation;
        return root;
    @Override
    public void onResume() {
        super.onResume();
        presenter.onResume();
        int orientation = getResources().getConfiguration().orientation;
        if (orientation == lastOrientation) {
            if (getUserVisibleHint()) {
                presenter.onViewBecomesVisible();
        lastOrientation = orientation;
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (presenter != null && isResumed() && isVisibleToUser) {
            presenter.onViewBecomesVisible();
    @Override public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_LAST_ORIENTATION, lastOrientation);
        
  • Mohammad Reza Norouzi
    Mohammad Reza Norouzi
    发布于 2013-01-12
    0 人赞同

    Detecting by focused view !

    This works for me

    public static boolean isFragmentVisible(Fragment fragment) {
        Activity activity = fragment.getActivity();
        View focusedView = fragment.getView().findFocus();
        return activity != null
                && focusedView != null
                && focusedView == activity.getWindow().getDecorView().findFocus();
        
    ATES
    focusedView returning null.
    @ATES 是的,我意识到有一些不同的情况,focusView会是空的。我会试着找到一种新的方法。
    Rukmal Dias
    Rukmal Dias
    发布于 2013-01-12
    0 人赞同

    我有同样的问题。 ViewPager 执行其他片段的生命周期事件,我无法改变这种行为。我使用片段和可用的动画写了一个简单的寻呼机。

    Ali Akram
    Ali Akram
    发布于 2013-01-12
    0 人赞同

    我用了这个,它很有效 !

    mContext.getWindow().getDecorView().isShown() //boolean
        
    Andoctorey
    Andoctorey
    发布于 2013-01-12
    0 人赞同

    我支持带有子片段的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;
        
    忘了说,一旦你把子片段添加到父片段中,设置fragment.setUserVisibleHint(true)。
    而且别忘了使用getChildFragmentManager()而不是getFragmentManager()来添加子片段。
    elevenfive
    elevenfive
    发布于 2013-01-12
    0 人赞同

    注意, setUserVisibleHint(false) 在活动/片段停止时不被调用。 你仍然需要检查start/stop以正确地 register/unregister 任何监听器/等。

    另外,如果你的片段以非可见状态开始,你会得到 setUserVisibleHint(false) ;你不希望在那里 unregister ,因为在这种情况下你以前从未注册过。

    @Override
    public void onStart() {
        super.onStart();
        if (getUserVisibleHint()) {
            // register
    @Override
    public void onStop() {
        if (getUserVisibleHint()) {
            // unregister
        super.onStop();
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser && isResumed()) {
            // register
            if (!mHasBeenVisible) {
                mHasBeenVisible = true;
        } else if (mHasBeenVisible){
            // unregister
        
    Malone
    Malone
    发布于 2013-01-12
    0 人赞同

    当我试图让一个计时器在viewpager中的片段出现在屏幕上供用户看到时启动时,我遇到了这个问题。

    计时器总是在用户看到该片段之前开始。 这是因为片段中的 onResume() 方法在我们看到片段之前被调用。

    我的解决方案是在 onResume() 方法中做一个检查。我想在片段8是view pagers的当前片段时调用某个方法'foo()'。

    @Override
    public void onResume() {
        super.onResume();
        if(viewPager.getCurrentItem() == 8){
            foo();
            //Your code here. Executed when fragment is seen by user.
    

    希望这有帮助。我已经看到这个问题出现了很多。这似乎是我见过的最简单的解决方案。很多其他的解决方案都与较低的API不兼容等等。

    Carl Smith
    我给这个答案投了下票,因为它使用了一个 "神奇的数字",这意味着它只对Piyush的应用程序有效。
    Martin Mbae
    Martin Mbae
    发布于 2013-01-12
    0 人赞同

    一个简单的实现方法是检查用户是否已登录 before 前往该片段。

    在你的MainActivity中,你可以这样做,在 在NavigationItemSelected上 method.

     case R.id.nav_profile_side:
                    if (User_is_logged_in) {
                        fragmentManager.beginTransaction()
                                .replace(R.id.content_frame
                                        , new FragmentProfile())
                                .commit();
                    }else {
                        ShowLoginOrRegisterDialog(fragmentManager);
                    break;
    

    然而,如果你使用的是导航抽屉,虽然我们没有进入ProfileFragment,但抽屉里的选择将变为Profile。

    To reset the selection to the current selection run the code below

            navigationView.getMenu().getItem(0).setChecked(true);
        
    Parthi
    Parthi
    发布于 2013-01-12
    0 人赞同

    可能会很晚。这对我来说是有效的。我稍微更新了@Gobar和@kris Solutions的代码。我们必须更新我们的 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;
        
    Osama Remlawi
    Osama Remlawi
    发布于 2013-01-12
    0 人赞同

    in Kotlin

    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        // Your code goes here..
        
    samus
    samus
    发布于 2013-01-12
    0 人赞同

    我覆盖了相关FragmentStatePagerAdapter的Count方法,让它返回总计数减去要隐藏的页数。

     public class MyAdapter : Android.Support.V13.App.FragmentStatePagerAdapter
         private List<Fragment> _fragments;
         public int TrimmedPages { get; set; }
         public MyAdapter(Android.App.FragmentManager fm) : base(fm) { }
         public MyAdapter(Android.App.FragmentManager fm, List<Android.App.Fragment> fragments) : base(fm)
             _fragments = fragments;
             TrimmedPages = 0;
         public override int Count
             //get { return _fragments.Count; }
             get { return _fragments.Count - TrimmedPages; }