75

I have a ViewPager, and I'd like to get the current selected and visible view, not a position.

  1. getChildAt(getCurrentItem) returns wrong View
  2. This works not all the time. Sometimes returns null, sometimes just returns wrong View.

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
    
        if (isVisibleToUser == true) { 
            mFocusedListView = ListView; 
        }
    }
    
  3. PageListener on ViewPager with getChildAt() also not working, not giving me the correct View every time.

How can i get current visible View?

View view = MyActivity.mViewPager.getChildAt(MyActivity.mViewPager.getCurrentItem()).getRootView();
ListView listview = (ListView) view.findViewById(R.id.ListViewItems);
Johnny Five
  • 987
  • 1
  • 14
  • 29
lacas
  • 13,928
  • 30
  • 109
  • 183

18 Answers18

140

I've figured it out. What I did was to call setTag() with a name to all Views/ListViews, and just call findViewWithTag(mytag), mytag being the tag.

Unfortunately, there's no other way to solve this.

Edric
  • 24,639
  • 13
  • 81
  • 91
lacas
  • 13,928
  • 30
  • 109
  • 183
  • 1
    This give me a hint. Thanks! – rahstame Aug 05 '13 at 11:08
  • 7
    I can't believe this is the best option but it works. I am just setting the index as the tag when the adapter creates the item. – respectTheCode Nov 13 '13 at 17:56
  • 14
    +1 to the absurdity of this solution, but it is definitely the best. Using the position as the tag in PagerAdapter.instantiateView and retrieving the View with findViewBy(getCurrentItem()) is the most elegant form of this hack. – nathanielwolf Aug 06 '14 at 23:31
  • another +1 @lacas for finding this solution – Addi Mar 12 '15 at 21:29
  • I didnt completely understand it. – M. Usman Khan Jan 20 '17 at 13:04
  • @usman for example imageView.setTag(R.string.firstname, "Abhishek"); You have to use application-specific resource id, otherwise there's an error https://stackoverflow.com/q/2859574/1645641 – nlt Jul 12 '17 at 03:24
  • 6
    Please tell me there's a better way to do this almost six years later!? – Graph Theory May 02 '18 at 00:37
  • Where do I set the tag? This is driving me crazy – Joel Broström Sep 12 '18 at 10:13
  • @JoelBroström A place where you inflating a view and returning it, it will be in your pager adapter if using simple adapter or it will will be in `onCreateView` of a fragment if you are using fragment pager adapter – Vaibhav Jani Dec 21 '18 at 13:06
  • @GraphTheory, The correct way to do this is by overrideing the `onViewAttachedToWindow(holder: Holder)` method in adapter class (extension of RecyclerView.Adapter). (my answer: https://stackoverflow.com/a/76838280/7835969) – Manishoaham Aug 04 '23 at 18:14
10

I just came across the same issue and resolved it by using:

View view = MyActivity.mViewPager.getFocusedChild();
ZeCodea
  • 1,071
  • 9
  • 26
  • 5
    This wont always work, sometimes focus is elsewhere even tho a view from ViewPager is currently displayed – Pimp Trizkit Mar 01 '13 at 21:16
  • That may be so, but works if you request focus on the page that gets visible – ZeCodea Mar 04 '13 at 09:56
  • 1
    Unless, im misunderstanding something here. What do you mean specifically by "request focus"? Because if i do `mViewPager.getChildAt(i).isFocused()` for all children, it reports `false` for all children. Which is probably because I'm putting this code into the options menu which is a part of the MainActivity, thus moving focus from the ViewPager. Therefore, this way wont work in certain situations. – Pimp Trizkit Mar 05 '13 at 00:13
  • yes, this might be a dialog popup or a Toast object. So use method isVisible() instead – CodeToLife Jan 21 '18 at 10:10
  • Doesn't seem to work for AndroidX ViewPager 1.0.0/Support library ViewPager 28.0.0 – Tim Kist Sep 06 '19 at 10:45
9

I use this method with android.support.v4.view.ViewPager

View getCurrentView(ViewPager viewPager) {
        try {
            final int currentItem = viewPager.getCurrentItem();
            for (int i = 0; i < viewPager.getChildCount(); i++) {
                final View child = viewPager.getChildAt(i);
                final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) child.getLayoutParams();

                Field f = layoutParams.getClass().getDeclaredField("position"); //NoSuchFieldException
                f.setAccessible(true);
                int position = (Integer) f.get(layoutParams); //IllegalAccessException

                if (!layoutParams.isDecor && currentItem == position) {
                    return child;
                }
            }
        } catch (NoSuchFieldException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalArgumentException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalAccessException e) {
            Log.e(TAG, e.toString());
        }
        return null;
    }
Dmitry Yablokov
  • 166
  • 1
  • 3
8

You can get the current element by accessing your list of itens from your adapter calling myAdapter.yourListItens.get(myViewPager.getCurrentItem()); As you can see, ViewPager can retrieve the current index of element of you adapter (current page).

If you is using FragmentPagerAdapter you can do this cast:

FragmentPagerAdapter adapter = (FragmentPagerAdapter)myViewPager.getAdapter();

and call

adapter.getItem(myViewPager.getCurrentItem());

This works very well for me ;)

Gilian
  • 422
  • 7
  • 12
  • 2
    Works only in case your adapter is FragmentPagerAdapter – Boris Strandjev Nov 19 '14 at 17:52
  • 23
    Note that `getItem()` is supposed to always return a new instance of a Fragment when subclassing `Fragment(State)PagerAdapter`. Therefore, this isn't right insofar as it just creates a new instance instead of returning the "old" one. – ComFreek Apr 03 '15 at 21:16
  • The above comment is wrong. Directly from the docs: "Return the Fragment associated with a specified position." Says nothing about returning a new Fragment. – worked Sep 28 '15 at 00:50
  • 2
    Your answer returns the Fragment, but for me, the Fragment is empty. adapter.getItem(myViewPager.getCurrentItem()).getView() returns null. – worked Sep 28 '15 at 00:56
2

During my endeavors to find a way to decorate android views I think I defined alternative solution for th OP's problem that I have documented in my blog. I am linking to it as the code seems to be a little bit too much for including everything here.

The solution I propose:

  • keeps the adapter and the view entirely separated
  • one can easily query for a view with any index form the view pager and he will be returned either null if this view is currently not loaded or the corresponding view.
Boris Strandjev
  • 46,145
  • 15
  • 108
  • 135
2

Use an Adapter extending PagerAdapter, and override setPrimaryItem method inside your PagerAdapter.

https://developer.android.com/reference/android/support/v4/view/PagerAdapter.html

class yourPagerAdapter extends PagerAdapter
{
    // .......

    @Override
    public void setPrimaryItem (ViewGroup container, int position, Object object)
    {
        int currentItemOnScreenPosition = position;
        View onScreenView = getChildAt(position);
    }

    // .......

}
AnCode
  • 97
  • 9
  • 2
    Doesn't answer the original question to get the actual view. Also, if you wanted the position why not use [getCurrentItem()](https://developer.android.com/reference/android/support/v4/view/ViewPager)? – Tim Kist Sep 06 '19 at 10:47
  • Yes. I forgot to write that to get the view you just have to use: getChildAt(currentItemOnScreenPosition). – AnCode Sep 18 '19 at 11:55
  • On the other hand, the getCurrentItem() function doesn't return the current selected and visible view, as the original question says, _getChildAt(getCurrentItem)_ returns wrong View. I think the getCurrentItem() function returns the item that is currently computed by the viewPager, and this item may not be the same that is currently on screen – AnCode Sep 18 '19 at 12:06
2
viewpager.getChildAt(0)

this always returns my currently selected view. this worked for me.

M.Usman
  • 2,049
  • 22
  • 25
1

If you do not have many pages and you can safely apply setOffscreenPageLimit(N-1) where N is the total number of pages without wasting too much memory then you could do the following:

public Object instantiateItem(final ViewGroup container, final int position) {      
    CustomHomeView RL = new CustomHomeView(context);
    if (position==0){
        container.setId(R.id.home_container);} ...rest of code

then here is code to access your page

((ViewGroup)pager.findViewById(R.id.home_container)).getChildAt(pager.getCurrentItem()).setBackgroundColor(Color.BLUE);

If you want you can set up a method for accessing a page

RelativeLayout getPageAt(int index){
    RelativeLayout rl =  ((RelativeLayout)((ViewGroup)pager.findViewById(R.id.home_container)).getChildAt(index));
    return rl;
}
Michael Kern
  • 639
  • 8
  • 15
  • 2
    `getChildAt(pager.getCurrentItem())` doesn't do what you want. For example ViewPager can have 1000 pages, but only 5 childen, so you're going out of bounds if current item is the last page. – fdermishin Jan 29 '18 at 07:47
  • @fdermishin this is true unless you have the option 'setOffscreenPageLimit(N-1)' where N is the number of pages. This is not advised though if you have many pages because it can be an unnecessary waste of memory – Michael Kern Nov 06 '19 at 02:58
1

Try this

 final int position = mViewPager.getCurrentItem();
    Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.rewards_viewpager + ":"
            + position);
Son Nguyen Thanh
  • 1,199
  • 15
  • 19
1

I had to do it more general, so I decided to use the private 'position' of ViewPager.LayoutParams

        final int childCount = viewPager.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = viewPager.getChildAt(i);
            final ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
            int position = 0;
            try {
                Field f = lp.getClass().getDeclaredField("position");
                f.setAccessible(true);
                position = f.getInt(lp); //IllegalAccessException
            } catch (NoSuchFieldException | IllegalAccessException ex) {ex.printStackTrace();}
            if (position == viewPager.getCurrentItem()) {
                viewToDraw = child;
            }
        }
Kamen Dobrev
  • 1,321
  • 15
  • 20
1

I'm using ViewPagerUtils from FabulousFilter:

ViewPagerUtils.getCurrentView(ViewPager viewPager)
  • I'm using this method and I can confirm that it works. – Aleksandar Acić Oct 23 '18 at 08:58
  • This is not part of the core android SDK. You are probably using a third party library. That is likely why you were downvoted. – aeskreis Oct 23 '18 at 20:36
  • 1
    Are you using this library? https://github.com/Krupen/FabulousFilter. This library has a ViewPagerUtils method. It uses the android.support.v4 namespace which is HIGHLY suspect. You should NEVER EVER use android namespaces for your classes, as it can lead to confusion (this being a perfect example of such confusion). It seems the author did this to access package protected fields, which once again is a terrible code practice. I would not recommend this method. – aeskreis Oct 23 '18 at 20:39
  • I wrote in the answer that it's the android support library v4. https://developer.android.com/topic/libraries/support-library/ – Aleksandar Acić Oct 24 '18 at 09:05
  • And the ViewPager is part of the Support Library so no additional dependency needs to be added. – Aleksandar Acić Oct 24 '18 at 09:20
  • ViewPager is part of the support library of course, but ViewPagerUtils does not exist in the support library. – aeskreis Oct 24 '18 at 14:25
0

is that your first activity on the screen or have you layered some above each other already?

try this:

findViewById(android.R.id.content).getRootView()

or just:

findViewById(android.R.id.content) 

also depending on what you want try:

((ViewGroup)findViewById(android.R.id.content)).getChildAt(0)
SunnySonic
  • 1,318
  • 11
  • 37
  • first twoo just give me the TAB 0 item, all the time, and the third code give me a null – lacas Oct 12 '12 at 08:22
  • tried this? this.findViewById(android.R.id.content).getRootView() Maybe you should give some more info about your activities and how you construct and move between them. – SunnySonic Oct 12 '12 at 16:58
  • None of those suggestions will work. The 3rd one will get a page in the pager but not the centre view but one to the left and the OP wanted the centred/current page. – Tim Kist Sep 09 '19 at 10:06
0

You can find fragment by system tag. It's work for me. I used it in OnMeasure function.

id - viewPager ID

position - fragment which you want to get

Important! You get this fragment if your fragment was created in adapter. So you must to check supportedFragmentManager.findFragmentByTag("android:switcher:" + id + ":" + position) nullify

You can get view like this:

supportedFragmentManager.findFragmentByTag("android:switcher:" + id + ":" + position).view

You shouldn't give custom tag in adapter

Aksenov Vladimir
  • 677
  • 1
  • 6
  • 16
0

You can get it by viewpager listener to get slected item position

viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{
        override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
            
        }

        override fun onPageSelected(position: Int) {
            
        }

        override fun onPageScrollStateChanged(state: Int) {
            
        }

    })
Tarif Chakder
  • 1,708
  • 1
  • 11
  • 10
0

Use this method.

View getCurrentView(ViewPager viewPager) {
        try {
            final int currentItem = viewPager.getCurrentItem();
            for (int i = 0; i < viewPager.getChildCount(); i++) {
                final View child = viewPager.getChildAt(i);
                final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) child.getLayoutParams();

                Field f = layoutParams.getClass().getDeclaredField("position"); //NoSuchFieldException
                f.setAccessible(true);
                int position = (Integer) f.get(layoutParams); //IllegalAccessException

                if (!layoutParams.isDecor && currentItem == position) {
                    return child;
                }
            }
        } catch (NoSuchFieldException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalArgumentException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalAccessException e) {
            Log.e(TAG, e.toString());
        }
        return null;
    }

it will may return null in androidx if anybody knows the solution comment here

Tariq Hussain
  • 409
  • 1
  • 5
  • 19
0

The correct way to do this is by overrideing the onViewAttachedToWindow(holder: Holder) method in adapter class (extension of RecyclerView.Adapter).

Also if you want to perform some operations (freeing up resources, stopping animation listeners etc) on the view which just swiped away, it can be done by overriding the onViewDetachedFromWindow(holder: Holder) in the adapter class.

Manishoaham
  • 601
  • 1
  • 5
  • 14
-3

Please check this

((ViewGroup))mViewPager.getChildAt(MyActivity.mViewPager.getCurrentItem()));

else verify this link.

Czechnology
  • 14,832
  • 10
  • 62
  • 88
Sathish Kumar
  • 63
  • 1
  • 4
  • not working, this get not that View that is visible sadly, and sometimes get null – lacas Oct 12 '12 at 08:37
  • 3
    This doesn't work. The range of `getChildAt()` is different than the range of `getCurrentItem()`. For example if your ViewPager shows 20 items and 1 offscreen page, then `getChildAt()`'s range is 0-2 while `getCurrentItem()`'s range is 0-19. You'd mostly get null return values. – foo64 Jun 07 '13 at 01:32
-3

If you examine carefully, there are at most 3 views saved by ViewPager. You can easily get the current view by

view     = MyActivity.mViewPager.getChildAt(1);
Akshay Vats
  • 170
  • 9
  • 1
    This doesn't work. What if the viewpager is showing its first or last page? What if there's more than 1 offscreen page? – foo64 Jun 06 '13 at 00:19
  • 1
    False, you can set ViewPager to cache more than 3 views with `setOffscreenPageLimit(int)` – zyamys Feb 23 '15 at 20:23