59

I would like to add or delete pages from my view pager dynamically. Is that possible?

Arnab Chakraborty
  • 7,442
  • 9
  • 46
  • 69

9 Answers9

26

Yes. You can add or delete views dynamically to the PagerAdapter that is supplying them to the ViewPager and call notifyDataSetChanged() from the PagerAdapter to alert the affected ViewPager about the changes. However, when you do so, you must override the getItemPosition(Object) of the PagerAdapter, that tells them whether the items they are currently showing have changed positions. By default, this function is set to POSITION_UNCHANGED, so the ViewPager will not refresh immediately if you do not override this method. For example,

public class mAdapter extends PagerAdapter {
    List<View> mList;

    public void addView(View view, int index) {
        mList.add(index, view);
        notifyDataSetChanged();
    }

    public void removeView(int index) {
        mList.remove(index);
        notifyDataSetChanged();
    }

    @Override
    public int getItemPosition(Object object)) {
        if (mList.contains(object) {
            return mList.indexOf(object);
        } else {
            return POSITION_NONE;
        }
    }
}

Although, if you simply want to add or remove the view temporarily from display, but not from the dataset of the PagerAdapter, try using setPrimaryItem(ViewGroup, int, Object) for going to a particular view in the PagerAdapter's data and destroyItem(ViewGroup, int, Object) for removing a view from display.

Zon
  • 18,610
  • 7
  • 91
  • 99
CodePro_NotYet
  • 621
  • 6
  • 17
18

Yes, since ViewPager gets the child Views from a PagerAdapter, you can add new pages / delete pages on that, and call .notifyDataSetChanged() to reload it.

Zsombor Erdődy-Nagy
  • 16,864
  • 16
  • 76
  • 101
  • 62
    in theory your answer is correct.. but in real world.. remove and add things from ViewPager is a pain.. specially with fragments.. – Guilherme Oliveira Dec 17 '14 at 13:39
  • 2
    You should override getItemPosition() in the Adapter – Davide Dec 11 '15 at 11:22
  • @GuilhermeOliveira I insert a view to the index 1 and invoke notifyDatasetChanged.But the viewpager doesn't refresh all the view, but initiate the last index.Do you know how to solve it ? – Allen Vork Oct 08 '16 at 02:44
  • Actually you can easily add fragments after your current position (right side of the ViewPager). BUT if you want to add before your current position (so the left side of the ViewPager) without jumping to it.. really tricky. I spent 2 days to figure out, but still don't know how to do it. – Zoltan Szilagyi Oct 27 '17 at 11:54
  • After Calling **notifyDataSetChange**, it goes blank page and also it re-instantiate views. What i need to do if i delete view from view pager adapter? i tried out with getItemPosition() but it doesn't work. Please provide any suggestion. Thanks. – Ritesh Adulkar Dec 18 '18 at 06:48
16

Yes, the code should be like this:

public int addPage(View view, int position) {
        if ((position >= 0) && (position < getSize())) {
            myPagerAdapter.mListViews.add(position, view);
            myPagerAdapter.notifyDataSetChanged();
            return position;
        } else {
            return -1;
        }
    }

public View removePage(int position) {
        if ((position < 0) || (position >= getSize()) || (getSize()<=1)) {
            return null;
        } else {
            if (position == mPager.getCurrentItem()) {
                if(position == (getSize()-1)) {
                    mPager.setCurrentItem(position-1);
                } else if (position == 0){
                    mPager.setCurrentItem(1);
                }
            }
            View tempView = myPagerAdapter.mListViews.remove(position);
            myPagerAdapter.notifyDataSetChanged();
            return tempView;
        }
    }

But there is a bug. If the current Item is 0, and to remove page 0, it will not refresh the screen instantly, I haven't found a solution for this.

tc007733
  • 199
  • 1
  • 6
  • 1
    Where does mListViews come from? – Muz Aug 28 '12 at 05:19
  • 1
    @Muz from what it looks like `mListViews` would be the List of Views in the class `myPagerAdapter` that would extend `FragmentPagerAdapter` since that would be the ideal area to store all the views (pages) for the ViewPager `mPager` – StrikeForceZero Sep 06 '12 at 21:08
  • 6
    @tc007733, it is not a bug, the key thing you need to override is getItemPosition(Object o) and return POSITION_NONE if this is no longer valid http://stackoverflow.com/questions/13664155/dynamically-add-and-remove-view-to-viewpager – DayDayHappy Oct 19 '13 at 03:12
4

Here's an alternative solution to this question. My adapter:

private class PagerAdapter extends FragmentPagerAdapter implements 
              ViewPager.OnPageChangeListener, TabListener {

    private List<Fragment> mFragments = new ArrayList<Fragment>();
    private ViewPager mPager;
    private ActionBar mActionBar;

    private Fragment mPrimaryItem;

    public PagerAdapter(FragmentManager fm, ViewPager vp, ActionBar ab) {
        super(fm);
        mPager = vp;
        mPager.setAdapter(this);
        mPager.setOnPageChangeListener(this);
        mActionBar = ab;
    }

    public void addTab(PartListFragment frag) {
        mFragments.add(frag);
        mActionBar.addTab(mActionBar.newTab().setTabListener(this).
                            setText(frag.getPartCategory()));
    }

    @Override
    public Fragment getItem(int position) {
        return mFragments.get(position);
    }

    @Override
    public int getCount() {
        return mFragments.size();
    }

    /** (non-Javadoc)
     * @see android.support.v4.app.FragmentStatePagerAdapter#setPrimaryItem(android.view.ViewGroup, int, java.lang.Object)
     */
    @Override
    public void setPrimaryItem(ViewGroup container, int position,
            Object object) {
        super.setPrimaryItem(container, position, object);
        mPrimaryItem = (Fragment) object;
    }

    /** (non-Javadoc)
     * @see android.support.v4.view.PagerAdapter#getItemPosition(java.lang.Object)
     */
    @Override
    public int getItemPosition(Object object) {
        if (object == mPrimaryItem) {
            return POSITION_UNCHANGED;
        }
        return POSITION_NONE;
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        mPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) { }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) { }

    @Override
    public void onPageScrollStateChanged(int arg0) { }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) { }

    @Override
    public void onPageSelected(int position) {
        mActionBar.setSelectedNavigationItem(position);
    }

    /**
     * This method removes the pages from ViewPager
     */
    public void removePages() {
        mActionBar.removeAllTabs();

                    //call to ViewPage to remove the pages
        vp.removeAllViews();
        mFragments.clear();

        //make this to update the pager
        vp.setAdapter(null);
        vp.setAdapter(pagerAdapter);
    }
}

Code to remove and add dynamically

//remove the pages. basically call to method removeAllViews from ViewPager
pagerAdapter.removePages();

pagerAdapter.addPage(pass your fragment);

After the advice of Peri Hartman, it started to work after I set null to ViewPager adapter and put the adapter again after the views removed. Before this the page 0 doesn't showed its list contents.

Community
  • 1
  • 1
thalespf
  • 380
  • 2
  • 8
3

I am sure you have created an adapter by extending PageAdapter, so there is one method:

 @Override
 public void destroyItem(View collection, int position, Object view) {
           ((ViewPager) collection).removeView((View) view);
 }

For detailed example for the same, just go through this example.

Paresh Mayani
  • 127,700
  • 71
  • 241
  • 295
2

First:override the pagerAdapter method "getItemPosition"

@Override
public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}

Second:remove the data bind with the adapter.and call adapter.notifydatachanged

howerknea
  • 355
  • 3
  • 12
1
@Bind(R.id.pager)
ViewPager pager;
int pos = pager.getCurrentItem();
pager.removeViewAt(pos);
Ragu Ram
  • 34
  • 2
  • 3
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – yennsarah Dec 08 '16 at 09:45
0

Based on other answers and other resources I've ended with this code.

CustomPagerAdapter:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CustomPagerAdapter extends PagerAdapter {

  private List<Fragment> pages = new ArrayList<>();
  private Map<Fragment, Integer> fragmentsPosition = new HashMap<>();

  private Fragment currentPrimaryItem;
  private FragmentManager fragmentManager;
  private FragmentTransaction currentTransaction;


  public CustomPagerAdapter(FragmentManager fragmentManager) {
    this.fragmentManager = fragmentManager;
  }

  @Override
  public Object instantiateItem(ViewGroup container, int position) {
    if (currentTransaction == null) {
      currentTransaction = fragmentManager.beginTransaction();
    }

    Fragment pageFragment = pages.get(position);
    String tag = pageFragment.getArguments().getString(MainActivity.FRAGMENT_TAG_ARG);
    Fragment fragment = fragmentManager.findFragmentByTag(tag);

    if (fragment != null) {
      if (fragment.getId() == container.getId()) {
        currentTransaction.attach(fragment);
      }
      else {
        fragmentManager.beginTransaction().remove(fragment).commit();
        fragmentManager.executePendingTransactions();
        currentTransaction.add(container.getId(), fragment, tag);
      }
    }
    else {
      fragment = pageFragment;
      currentTransaction.add(container.getId(), fragment, tag);
    }

    if (fragment != currentPrimaryItem) {
      fragment.setMenuVisibility(false);
      fragment.setUserVisibleHint(false);
    }

    return fragment;
  }

  @Override
  public int getCount() {
    return pages.size();
  }

  @Override
  public void destroyItem(ViewGroup container, int position, Object object) {
    if (currentTransaction == null) {
      currentTransaction = fragmentManager.beginTransaction();
    }

    currentTransaction.detach((Fragment) object);
  }

  @Override
  public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment) object;

    if (fragment != currentPrimaryItem) {
      if (currentPrimaryItem != null) {
        currentPrimaryItem.setMenuVisibility(false);
        currentPrimaryItem.setUserVisibleHint(false);
      }

      if (fragment != null) {
        fragment.setMenuVisibility(true);
        fragment.setUserVisibleHint(true);
      }

      currentPrimaryItem = fragment;
    }
  }

  @Override
  public void finishUpdate(ViewGroup container) {
    if (currentTransaction != null) {
      currentTransaction.commitAllowingStateLoss();
      currentTransaction = null;
      fragmentManager.executePendingTransactions();
    }
  }

  @Override
  public boolean isViewFromObject(View view, Object object) {
    return ((Fragment) object).getView() == view;
  }

  @Override
  public int getItemPosition(Object o) {
    Integer result = fragmentsPosition.get(o);

    if (result == null) {
      return PagerAdapter.POSITION_UNCHANGED;
    }

    return result;
  }

  // ---------------------------------- Page actions ----------------------------------

  public void addPage(Fragment fragment) {
    fragmentsPosition.clear();
    pages.add(fragment);
    notifyDataSetChanged();
  }

  public void removePage(int position) {
    fragmentsPosition.clear();

    Fragment pageFragment = pages.get(position);
    String tag = pageFragment.getArguments().getString(MainActivity.FRAGMENT_TAG_ARG);

    Fragment fragment = fragmentManager.findFragmentByTag(tag);

    if (fragment != null) {
      fragmentsPosition.put(fragment, PagerAdapter.POSITION_NONE);
    }

    for (int i = position + 1; i < pages.size(); i++) {
      pageFragment = pages.get(i);
      tag = pageFragment.getArguments().getString(MainActivity.FRAGMENT_TAG_ARG);
      fragment = fragmentManager.findFragmentByTag(tag);

      if (fragment != null) {
        fragmentsPosition.put(fragment, i - 1);
      }
    }

    pages.remove(position);
    notifyDataSetChanged();
  }

}

MainActivity:

import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

  public static final String FRAGMENT_TAG_ARG = "tag";

  private CustomPagerAdapter mCustomPagerAdapter;

  private ViewPager mViewPager;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mCustomPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager());
    mCustomPagerAdapter.addPage(MainFragment.newInstance("Main_Title"));
    mCustomPagerAdapter.addPage(SecondaryFragment.newInstance("Secondary_Title"));

    mViewPager = (ViewPager) findViewById(R.id.container);
    mViewPager.setAdapter(mCustomPagerAdapter);
  }

}

To remove pages:

mCustomPagerAdapter.removePage(1);

MainFragment:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class MainFragment extends Fragment {

  public static final String FRAGMENT_TAG = "MainFragment";

  public static MainFragment newInstance(String text) {
    return newInstance(text, FRAGMENT_TAG);
  }

  public static MainFragment newInstance(String text, String tag) {
    MainFragment fragment = new MainFragment();
    Bundle args = new Bundle();
    args.putString("text", text);
    args.putString(MainActivity.FRAGMENT_TAG_ARG, tag + "_" + fragment.hashCode());
    fragment.setArguments(args);
    return fragment;
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);
    TextView textView = (TextView) rootView.findViewById(R.id.section_label);
    textView.setText(getArguments().getString("text"));
    return rootView;
  }

}

SecondaryFragment has the same code.

The layouts are simple ViewPager/Fragment layouts with android.support.v4.view.ViewPager with id container and Fragment TextView with id section_label.

Resources:

mortalis
  • 2,060
  • 24
  • 34
0

you have to set the adapter to viewpager again, then it will refresh the content.

removeView(int pos) in my PagerAdaper

public void removeView(int index) {
       imageFileNames.remove(index);
       notifyDataSetChanged();
}

wherever I am removing the file I have to do like this

imagePagerAdapter.removeView(currentPosition);
viewPager.setAdapter(imagePagerAdapter);

EDIT:

This below method is effective, you can apply the below one.

public void updateView(int pos){
      viewPager.setAdapter(null);
      imagePagerAdapter =new ImagePagerAdapter(YOUR_CONTEXT,YOUR_CONTENT);
      viewPager.setAdapter(imagePagerAdapter);
      viewPager.setCurrentItem(pos);
}

replace YOUR_CONTEXT with your context and your content with your content name i.e. updated list or something.

sai Pavan Kumar
  • 1,129
  • 12
  • 20