20

I am using a viewpager to display some text across multiple pages. I am trying to get the current view an I select a new page. The reason I want to get the current view is because based on the page number I am changing some properties of some view components like textview, image etc. I am using the below code for the same

ViewPager mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
View CurrView;
OnPageChangeListener pageChangelistener = new OnPageChangeListener() {
  @Override
       public void onPageSelected(int pageSelected) {
          currView = mPager.getChildAt(mPager.getCurrentItem());
      myTextView = (TextView)currView.findViewById(R.id.myTextView);
              loadBookmarkSetting(pageSelected);//do some changes in myTextView    properties based on the page number  }
 mPager.setOnPageChangeListener(pageChangelistener);

Now the problem I am facing that after I scroll 3 pages and when I come to 4th page, i get nullpointer exception on the line "myTextView = (TextView)currView.findViewById(R.id.myTextView);". This is so becuase currView is null. Any ideas if I am doing something wrong here. Is there any other way to capture current view(page) in viewpager so as I can do changes on the view based on what page number I am on?

user1938357
  • 1,466
  • 3
  • 20
  • 33

5 Answers5

66

You can use the setTag with the view you are returning in your instantiateItem method(PagerAdapter).

So, when you are instantiating your views in PagerAdapter the method is also instantiateItem(ViewGroup container, int position)), you should use setTag to your view.

Like this:

view.setTag("myview" + position);
return view;

when you need the current view:

View view = (View) pager.findViewWithTag("myview" + pager.getCurrentItem());
Nick
  • 9,285
  • 33
  • 104
  • 147
Raj008
  • 3,539
  • 2
  • 28
  • 26
  • 3
    Not clear decision, because instantiateItem(...) returns Fragment under Object interface. And we can use Fragemnt.getView() only after committing transaction. – ultraon Sep 21 '15 at 19:05
  • In one very special case - inside onPageSelected() callback of ViewPager.SimpleOnPageChangeListener, pager.findViewWithTag(my_tag) will probably return null because this callback first get called before any other items are created. But the following calls are ok because view pager will create other items ahead of showing them. – StoneLam May 08 '18 at 08:46
4

You use this approach:

@Nullable
    public static View getActiveView(@Nonnull final ViewPager viewPager) {
        final PagerAdapter adapter = viewPager.getAdapter();
        if (null == adapter || adapter.getCount() == 0 || viewPager.getChildCount() == 0) {
            return null;
        }

        int position;
        final int currentPosition = viewPager.getCurrentItem();

        for (int i = 0; i < viewPager.getChildCount(); i++) {
            final View child = viewPager.getChildAt(i);
            final LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            if (layoutParams.isDecor) {
                continue;
            }
            final Field positionField;
            try {
                positionField = LayoutParams.class.getDeclaredField("position");
                positionField.setAccessible(true);
                position = positionField.getInt(layoutParams);
            } catch (NoSuchFieldException e) {
                break;
            } catch (IllegalAccessException e) {
                break;
            }
            if (position == currentPosition) {
                return child;
            }
        }
        return null;
    }
ultraon
  • 2,220
  • 2
  • 28
  • 27
1

You are getting null pointer exception because you have set the offscreenPageLimit to 3.The viewpager will store only 3 pages.mPager.getChildAt(4) will get a null. To set textview, you can use fragment manager of adapter to get all fragments and the get the view of the fragment at position.

adapter.fragmentManager.fragments[position1].view
ozmank
  • 763
  • 1
  • 8
  • 23
0

I added a SparseArray to my Adapter and add the view in instantiateItem() and remove it in destroyItem()

val views = SparseArray<View>()

...

override fun instantiateItem(container: ViewGroup, position: Int): Any 
{
    //...

    container.addView(view)
    views.put(position, view)
    return view
}

override fun destroyItem(container: ViewGroup, position: Int, obj: Any) 
{
    views.remove(position)
    container.removeView(obj as View)
}

fun showFooter(currentItem: Int) {
    views[currentItem].footer_layout.animate().alpha(1f)
}

fun hideFooter(currentItem: Int) {
    views[currentItem].footer_layout.animate().alpha(0f)
}

And then I can call methods on the adapter:

viewPager.addOnPageChangeListener(object: ViewPager.OnPageChangeListener {
    override fun onPageScrollStateChanged(state: Int) {
        when (state) {
            SCROLL_STATE_IDLE -> adapter.showFooter(viewPager.currentItem)
            SCROLL_STATE_DRAGGING -> adapter.hideFooter(viewPager.currentItem)
        }
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

    override fun onPageSelected(position: Int) {}

})
Boy
  • 7,010
  • 4
  • 54
  • 68
-1

The reason why your current view is null is because the pager adapter starts to destroy its items for memory efficiency purposes. One way i have found would work is to override the destroyItem() method of the pager adapter and save your data either through a list or by parceable class.