74

I have a ViewPager, each page is a Fragment view. I want to test if a fragment is in a visible region. the Fragment.isVisible only test

  • the fragment is attached to a activity
  • the fragment is set to visible
  • the fragment has been added to a view

The ViewPager will create 3 (by default) fragment and all three of them meet the above criteria, but only one is actually visible to the user (the human eyes)

David S.
  • 10,578
  • 12
  • 62
  • 104

10 Answers10

67

This is what I use to determine the visibility of a fragment.

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");
    }
}
Jake Graham Arnold
  • 1,416
  • 2
  • 19
  • 40
miroslavign
  • 2,033
  • 2
  • 24
  • 26
  • This does not work as per documentation: "Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore" – Edison May 23 '13 at 15:38
  • 1
    Good solution (+1) but code can be simplified: `public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); m_iAmVisible = false; //default to not visible if (isVisibleToUser) { m_iAmVisible = true; } }` – PeteH May 26 '13 at 06:04
  • 2
    simplified is: public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); m_iAmVisible = isVisibleToUser;} – Kasas Jul 10 '13 at 14:45
  • 30
    even simpler, `getUserVisibleHint()` – Leonardo Pinto Jan 08 '14 at 16:45
  • 1
    THIS HELPS A LOT THANK YOU! – Lazar Kukolj Apr 09 '16 at 23:03
19

You're right there is a better way to do this!

Have a look at the FragmentPagerAdapter javadoc online and you'll see there is a method setPrimaryItem(ViewGroup container, int position, Object object):void doing exactly what you need.

From the javadoc

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

Called to inform the adapter of which item is currently considered to be the "primary", that is the one show to the user as the current page.

Parameters container The containing View from which the page will be removed. position The page position that is now the primary. object The same object that was returned by instantiateItem(View, int).

Note on scroll state

Now if you implement this and start debugging to get a feel of when exactly this is called you'll quickly notice this is triggered several times on preparing the fragment and while the user is swiping along.

So it might be a good idea to also attach a ViewPager.OnPageChangeListener and only do what has to be done once the viewpagers scroll state becomes SCOLL_STATE_IDLE again.

hcpl
  • 17,382
  • 7
  • 72
  • 73
  • 1
    this approach works great if one extends the `Application` class and has to test whether a particular UI is showing. I just ended up using several booleans to test whether the app was backgrounded, and whether a particular fragment was showing. – Someone Somewhere May 04 '14 at 06:58
9

For my purposes, it worked to use ViewPager.OnPageChangeListener.onPageSelected() in conjunction with Fragment.onActivityCreated() to perform an action when the Fragment is visible. Fragment.getUserVisibleHint() helps too.

Leo Landau
  • 1,785
  • 17
  • 25
3

I'm using "setMenuVisibility"-Method for resolving this Problem. As every Fragment can have actionbar-items this is the part where you can determine which Fragment is currently visible to the user.

@Override
public void setMenuVisibility(final boolean visible) {
    super.setMenuVisibility(visible);
    if (!visible) {
        //not visible anymore
    }else{
        yay visible to the user
    }
}
Frame91
  • 3,670
  • 8
  • 45
  • 89
3

What is wrong with using getView().isShown() to find out if a Fragment is actually visible?

awy
  • 5,271
  • 5
  • 23
  • 28
  • Have you tested your idea? I think [this](http://stackoverflow.com/questions/6796299/view-getvisibility-isshown-return-incorrect-visibility) post pointed out the same idea. – David S. Apr 16 '15 at 00:01
  • Yes. It works for me, as suggested in the linked post. – awy Apr 17 '15 at 06:12
3
isVisible() 

Can still return true even if the fragment is behind an activity.

I'm using the following:

if (getView() != null && getView().isShown()) {
//your code here
}
vvbYWf0ugJOGNA3ACVxp
  • 1,086
  • 10
  • 23
  • 1
    according to [this](https://stackoverflow.com/questions/6796299/view-getvisibility-isshown-return-incorrect-visibility) , `isShown` is similar to `getVisibility()` so it can still return true if `VISIBLE` but behind an activity – Mysterious_android Nov 01 '18 at 00:24
2

If you know what "page" each fragment is attached to you could use ViewPager.getCurrentItem() to determine which fragment is "visible".

roflharrison
  • 2,300
  • 23
  • 26
0

In my case i a have to do some work on the first fragment when the fragment is visible to the user

 @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();
        }
    }
}
W00di
  • 954
  • 12
  • 21
0

setUserVisibleHint probably may not be called, onHiddenChanged may be called not every time when another fragment is being closed. So, you may rely on onResume (and onPause), but it is usually called too often (for example, when you turn on a device screen). Also in some situations it is not called, you should manage current fragment in host activity and write:

if (currentFragment != null) {
    currentFragment.onResume();
}
CoolMind
  • 26,736
  • 15
  • 188
  • 224
0

Kotlin:

if (userVisibleHint) {
    // the fragment is visible
} else {
    // the fragment is not visible
}

Java

if (getUserVisibleHint()) {
    // the fragment is visible
} else {
    // the fragment is not visible
}

https://developer.android.com/reference/android/app/Fragment.html#getUserVisibleHint()

https://stackoverflow.com/a/12523627/2069407

s-hunter
  • 24,172
  • 16
  • 88
  • 130