Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android ViewPager: Move any page to end programatically?

Using the Viewpager in Android, is it possible to programmatically move any page to the end? For example, I have five pages and want to move page #2 to the last position (5th position) so page 3 becomes 2, 4 becomes 3, and 5 becomes 4?

thanks

like image 997
mraviator Avatar asked Sep 07 '12 15:09

mraviator


2 Answers

Yes. I'll try and answer your case by showing how I did it, and I'll show an example for your case below my code sample.

Basically, to accomplish this you have to keep track which position your Fragments have. Below is the implementation I used for my FragmentPagerAdapter, which uses an ArrayList as its data source.

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    private HashMap<Long, Fragment> mItems
                    = new HashMap<Long, Fragment>();

    private ArrayList<MyObject> dataset;

    public MyFragmentPagerAdapter(ArrayList<MyObject> objects) {
        this.dataset = objects;
    }

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

    @Override
    public Fragment getItem(int position) {
        long id = getItemId(position);

        if(mItems.get(id) != null) {
            // caching to prevent multiple instances of the same fragment
            // for the same position/id
            return mItems.get(id);
        }

        Fragment f = Fragment.newInstance();

        mItems.put(id, f);

        return f;
    }

    @Override
    public long getItemId(int position) {
        // return a unique id
        return dataset.get(position).getUniqueId();
    }

    @Override
    public int getItemPosition(Object object) {
        /*
         * Purpose of this method is to check whether an item in the adapter
         * still exists in the dataset and where it should show.
         * For each entry in dataset, request its Fragment.
         * 
         * If the Fragment is found, return its (new) position. There's
         * no need to return POSITION_UNCHANGED; ViewPager handles it.
         * 
         * If the Fragment passed to this method is not found, remove all
         * references and let the ViewPager remove it from display by
         * by returning POSITION_NONE;
         */
        Fragment f = (Fragment) object;

        for(int i = 0; i < getCount(); i++) {

            Fragment item = (Fragment) getItem(i);
            if(item.equals(f)) {
                // item still exists in dataset; return position
                return i;
            }
        }

        // if we arrive here, the data-item for which the Fragment was created
        // does not exist anymore.

        // Also, cleanup: remove reference to Fragment from mItems
        for(Map.Entry<Long, MainListFragment> entry : mItems.entrySet()) {
            if(entry.getValue().equals(f)) {
                mItems.remove(entry.getKey());
                break;
            }
        }

        // Let ViewPager remove the Fragment by returning POSITION_NONE.
        return POSITION_NONE;
    }
}

Now if you remove an item from the dataset (this.dataset) and call notifyDataSetChanged() on your instance of MyFragmentPagerAdapter, it will remove the item from the ViewPager (even if it's currently being viewed).

Let's say this.dataset contains 5 items, and you want to move #2 to the end of the ViewPager. To accomplish this, you'll have to position item#2 to the end of your datasource (either via Collection.Sort or some other way). I'll just show you the easy way.

ArrayList<MyObject> list = new ArrayList<>();
MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(list);
viewpager.setAdapter(adapter);

...

MyObject item = list.get(2);
list.remove(item);
list.add(item); // now it's positioned at the end of the list
adapter.notifyDataSetChanged(); // voilá, that should do the trick!

adapter.notifyDataSetChanged() eventually calls viewpager.dataSetChanged(), which in turn calls adapter.getItemPosition(..) on each of its pages. The result of that method call determines if and where the page (Fragment in this case) will show up.

like image 189
Reinier Avatar answered Nov 11 '22 11:11

Reinier


I have just been reading up on all this.

The usual way of using a ViewPager is by having a PagerAdapter class that feeds it the right pages at the right moment. There are nice subclasses of PagerAdapter, FragmentPagerAdapter and FragmentStatePagerAdapter which are easier to use.

However in order to be able to change the page order you are going to have to write your own subclass of PagerAdapter. Basically there are two ways the ViewPager knows which page you are on: the page number, and a key object that the adapter has given it. Hence you ought to be able to change the order without the ViewPager getting too lost.

The gory details of how it is done are on this page. I haven't yet tried to but I will in the weeks to come. I think that page doesn't say everything. It has no mention of a getItem() method that most Adapter classes must have. So I really don't yet see how the pages get added to the ViewPager.

Time to find and read some sample code.

like image 25
jpeg729 Avatar answered Nov 11 '22 11:11

jpeg729