1

My adapter for the ViewPager needs to be reset according to the current active page.I want to do it using OnPageChangeListener. A part of the code of my adapter is like:

    class CustomPagerAdapter extends PagerAdapter {
            static int currpage = 0; // current selected page
            ......
            @Override
            public Object instantiateItem(ViewGroup collection, int position) {     
                LayoutInflater inflater = LayoutInflater.from(mContext);
                View layout = inflater.inflate(R.layout.layout_home_viewpager, collection, false);

               // some code that changes layout dynamically    
               // according to variable position and currpage
               ......

               collection.addView(layout);
               return layout;
            }
    }

And here is the code for my viewpager(inside OnCreateView of a fragment):

    ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            CustomPagerAdapter.currpage = position;
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    };
    viewPager.addOnPageChangeListener(onPageChangeListener);
    viewPager.setAdapter(customPagerAdapter);

The following code will only be called once(When creating view of the fragment):

     viewPager.setAdapter(customPagerAdapter);

I intend to call setadapter whenever the active is changed.But if I change the code to this :

    @Override
    public void onPageSelected(int position) {
        CustomPagerAdapter.currpage = position; // flag for setAdapter
        viewPager.setAdapter(customPagerAdapter);
    }

the viewpager will be unable to slide.

Since the only way to detect page changing is register a listener to viewPager and we can't call setAdapter inside the method of our listener, What will be the best way to reset adapter for viewpager when the selected page is changed ?

programforjoy
  • 391
  • 3
  • 12

3 Answers3

1

You could invoke setAdapter() when user finished slide.

@Override
public void onPageScrollStateChanged(int state) {
    if (state == SCROLL_STATE_IDLE) {
        setAdapter(adapter);
    }
}
1

I don't quite understand what you mean with "needs to be reset". If you reset the adapter the viewpager will go back to the first page, which is totally not what you want the viewpager to do when the user changes the page.

But the problem is deeper. A ViewPager doesn't work like a ListView, it doesn't recycle its views, or rebinds them according to a change in the underlying dataset. It's basically just a ViewGroup with paging and swiping functionality. In practice, what this means is that you need to keep track of your views, their positions and bind them to your data outside of the onInstantiate and onDestroy methods, so basically your approach isn't optimal considering the limitations of the API you are using.

My suggestion would be to change your adapter and hold a reference to your views using a List, move your view logic to the outside of your instantiate method and call it everytime a page changes.

Here's a functioning example:

 class CustomPagerAdapter extends PagerAdapter {
        List<View> mViews = new ArrayList<>;
        ......
        @Override
        public Object instantiateItem(ViewGroup collection, int position) {     
            LayoutInflater inflater = LayoutInflater.from(mContext);
            View layout = inflater.inflate(R.layout.layout_home_viewpager, collection, false);
           mViews.add(layout);
           collection.addView(layout);
           populateView(layout);
           return layout;
        }

        public void populateView(int position){
           if(position < mView.size()){
              populateView(mViews.get(position));
           }
        }

        private void populateView(View layout){
           // some code that changes layout dynamically    
           // according to variable position and currpage
           ......
        }
}

And then, on your listener:

@Override
public void onPageSelected(int position) {
    customPagerAdapter.populateView(position);
}

This should fix your issue.

  • The idea is good.But I found the method instantiateItem very tricky.It is called many times when you are sliding into different pages.And actually you can't use mViews to trace references of views in viewpager because you are updating these views and instantiateItem will be called from time to time. I found that the size of mViews keeps growing, even larger than the sum of all pages. – programforjoy Jul 09 '16 at 15:33
  • This is normal. You need to remove your view from mViews in the onDestroy method. –  Jul 10 '16 at 11:03
0

I have found a solution to my posted question. Check this question: ViewPager PagerAdapter not updating the View

All we need is to call setTag() method in instantiateItem() when instantiating a new view. Then you can use findViewWithTag() to find the view you want to update.

Code will be like:

     public Object instantiateItem(ViewGroup collection, int position) {     
            LayoutInflater inflater = LayoutInflater.from(mContext);
            View layout = inflater.inflate(R.layout.layout_home_viewpager, collection, false);
            layout.setTag(position);


            ......

            collection.addView(layout);
            return layout;
        }        

    @Override
    public void onPageSelected(int position) {
            View layout = viewPager.findViewWithTag(position);
            // code that updates the selected page ......
    }
Community
  • 1
  • 1
programforjoy
  • 391
  • 3
  • 12