Android ViewPager get the current View
Asked Answered
U

19

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);
Usurious answered 12/10, 2012 at 8:8 Comment(0)
U
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.

Usurious answered 12/10, 2012 at 12:3 Comment(10)
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.Pitts
+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.Dysgenics
another +1 @Usurious for finding this solutionSarazen
I didnt completely understand it.Northwestwards
@usman for example imageView.setTag(R.string.firstname, "Abhishek"); You have to use application-specific resource id, otherwise there's an error https://mcmap.net/q/111806/-the-key-must-be-an-application-specific-resource-id/1645641Hoxie
Please tell me there's a better way to do this almost six years later!?Asymptotic
Where do I set the tag? This is driving me crazyEndless
@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 adapterOverpowering
@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://mcmap.net/q/110254/-android-viewpager-get-the-current-view)Psychedelic
Could you show a code example please? Or could one of the commentators post an answer?Pinchbeck
C
10

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

View view = MyActivity.mViewPager.getFocusedChild();
Choice answered 30/1, 2013 at 19:3 Comment(5)
This wont always work, sometimes focus is elsewhere even tho a view from ViewPager is currently displayedSahib
That may be so, but works if you request focus on the page that gets visibleChoice
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.Sahib
yes, this might be a dialog popup or a Toast object. So use method isVisible() insteadLilongwe
Doesn't seem to work for AndroidX ViewPager 1.0.0/Support library ViewPager 28.0.0Greaser
A
10

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;
    }
Agreeable answered 27/5, 2019 at 12:14 Comment(1)
Thank you so much. It's exactly what I wantCabal
M
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 ;)

Malisamalison answered 17/7, 2013 at 15:39 Comment(4)
Works only in case your adapter is FragmentPagerAdapterAngelinaangeline
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.Conference
The above comment is wrong. Directly from the docs: "Return the Fragment associated with a specified position." Says nothing about returning a new Fragment.Clause
Your answer returns the Fragment, but for me, the Fragment is empty. adapter.getItem(myViewPager.getCurrentItem()).getView() returns null.Clause
A
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.
Angelinaangeline answered 2/12, 2014 at 14:16 Comment(0)
D
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);
    }

    // .......

}
Dapper answered 15/2, 2018 at 12:35 Comment(3)
Doesn't answer the original question to get the actual view. Also, if you wanted the position why not use getCurrentItem()?Greaser
Yes. I forgot to write that to get the view you just have to use: getChildAt(currentItemOnScreenPosition).Dapper
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 screenDapper
B
2
viewpager.getChildAt(0)

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

Boxberry answered 16/2, 2020 at 7:26 Comment(0)
H
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;
}
Hooten answered 2/2, 2014 at 16:47 Comment(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.Kele
@Kele 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 memoryHooten
B
1

Try this

 final int position = mViewPager.getCurrentItem();
    Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.rewards_viewpager + ":"
            + position);
Bobette answered 9/11, 2016 at 7:14 Comment(0)
J
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;
            }
        }
Jeromejeromy answered 22/5, 2017 at 19:18 Comment(0)
S
1

I'm using ViewPagerUtils from FabulousFilter:

ViewPagerUtils.getCurrentView(ViewPager viewPager)
Sporran answered 18/7, 2018 at 10:2 Comment(6)
I'm using this method and I can confirm that it works.Churchgoer
This is not part of the core android SDK. You are probably using a third party library. That is likely why you were downvoted.Confirmed
Are you using this library? 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.Confirmed
I wrote in the answer that it's the android support library v4. developer.android.com/topic/libraries/support-libraryChurchgoer
And the ViewPager is part of the Support Library so no additional dependency needs to be added.Churchgoer
ViewPager is part of the support library of course, but ViewPagerUtils does not exist in the support library.Confirmed
P
1

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.

Psychedelic answered 4/8, 2023 at 18:10 Comment(1)
This absolutely saved me for the final project of my Android class due in 20 hours. Thank you so much!Pinchbeck
H
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)
Harakiri answered 12/10, 2012 at 8:11 Comment(3)
first twoo just give me the TAB 0 item, all the time, and the third code give me a nullUsurious
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.Harakiri
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.Greaser
T
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

Topmast answered 29/7, 2018 at 21:45 Comment(0)
I
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) {
            
        }

    })
Isiah answered 11/10, 2021 at 9:38 Comment(0)
A
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

Archy answered 10/1, 2022 at 6:27 Comment(0)
O
0

The issue is you can't call getChildAt(getCurrentItem()) directly on the ViewPager. You should call it on the underlying RecyclerViewImpl which exists at getChildAt(0).

View view = viewPager.getChildAt(0).getChildAt(viewPager.getCurrentItem);
Ornas answered 26/9, 2023 at 13:7 Comment(0)
C
-3

Please check this

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

else verify this link.

Coumas answered 12/10, 2012 at 8:28 Comment(2)
not working, this get not that View that is visible sadly, and sometimes get nullUsurious
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.Foreordination
I
-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);
Illinium answered 12/12, 2012 at 22:9 Comment(2)
This doesn't work. What if the viewpager is showing its first or last page? What if there's more than 1 offscreen page?Foreordination
False, you can set ViewPager to cache more than 3 views with setOffscreenPageLimit(int)Hetrick

© 2022 - 2024 — McMap. All rights reserved.