11

I know there are some topics about this here already but I could not find a solution which I could get to work for my case.

I have a working sliding gallery using a custom FragmentActivity and FragmentPagerAdapter which holds a list of Fragments.

Within the FragmentActivity is a ImageView "delete". If clicked, the function deleteMedia() is called which then should remove the current Fragment and the following Fragment should be displayed. How would I have to do that in my example?

FragmentActivity:

public class GalleryPagerActivity extends FragmentActivity implements OnClickListener {

    private Intent intent;
    private SharedPreferences settings;
    private PagerAdapter mPagerAdapter;
    private ViewPager mPager;
    private List<Fragment> fragments;
    private List<WhiteboardMedia> wiList;

    private int selectedPosition;
    private LinearLayout llTop;
    private TextView tvTop;
    private ImageView delete;
    private ImageView share;
    private TextView tvCounter;
    private TextView tvFilename;
    private TextView tvFilesize;
    private TextView tvDate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            super.setContentView(R.layout.gallery_pager);

            intent = getIntent();

            Type collectionType = new TypeToken<List<WhiteboardMedia>>(){}.getType();

            wiList = gson.fromJson(intent.getStringExtra("wiList"), collectionType);
            selectedPosition = intent.getIntExtra("position", 1);

            llTop = (LinearLayout) findViewById(R.id.llTop);
            llTop.setOnClickListener(this);
            tvTop = (TextView) findViewById(R.id.tvTop);
            tvTop.setOnClickListener(this);
            delete = (ImageView) findViewById(R.id.imgDelete);
            delete.setOnClickListener(this);
            share = (ImageView) findViewById(R.id.imgShare);
            share.setOnClickListener(this);

            tvCounter = (TextView) findViewById(R.id.tvCounter);
            tvFilename = (TextView) findViewById(R.id.tvFilename);
            tvFilesize = (TextView) findViewById(R.id.tvFilesize);
            tvDate = (TextView) findViewById(R.id.tvDate);

            createContextMenu();
            initDropbox();
        } catch (Exception e) {
            Log.e("GalleryPagerActivity", e.getLocalizedMessage());
        }
    }

    /**
     * Initialise the pager
     */
    private void initialisePager() {
        mPager = (ViewPager) super.findViewById(R.id.viewpager);
        mPager.setAdapter(this.mPagerAdapter);
        mPager.setOnPageChangeListener(new GalleryPageListener(tvCounter, tvFilename, tvFilesize, tvDate, wiList));

        mPager.setCurrentItem(selectedPosition, true);
        updatePage(selectedPosition);
    }

    public void updatePage(int position)
    {
        int focusedPage = position + 1;
        Log.i("onPageSelected", "page selected " + position);

        WhiteboardMedia wiImage = wiList.get(position);

        String imageDate = "N/A";
        try {
            Date dateTaken= new Date(); //wiImage.getDate();
            SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd");
            imageDate = sdf.format(dateTaken);
        } catch (Exception e) {
        }

        try {
            tvCounter.setText(focusedPage + "/" + wiList.size());
            tvFilename.setText(wiImage.getFilename());
            tvFilesize.setText(wiImage.getSize() + "a");
            tvDate.setText(imageDate);
        } catch (Exception e) {
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    private WhiteboardMedia getActiveWhiteboardImage() {
        return wiList.get(mPager.getCurrentItem());
    }

    private final int DELETE = 1;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(1, DELETE, 2, R.string.delete).setIcon(R.drawable.menu_btn_trash);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case DELETE:
            deleteMedia();
            return true;
        }
        return super.onContextItemSelected(item);
    }

    @Override
    public void onClick(View v) {
        if (v == delete) {
            deleteMedia();
        }
    }

    private void deleteMedia() {
        // TODO delete the active Fragment and display the next Fragment in the list
    }

    /******************************************************************************
     * Context Menu
     *****************************************************************************/
    private void createContextMenu() {
        // context menu stuff
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        // stuff
    }

}

FragmentPagerAdapter:

public class GalleryPagerAdapter extends FragmentPagerAdapter {

private final List<Fragment> fragments;

public GalleryPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
    super(fm);
    this.fragments = fragments;
}

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

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

Thanks for help!

Bugs Happen
  • 2,169
  • 4
  • 33
  • 59
Dominik
  • 1,703
  • 6
  • 26
  • 46

5 Answers5

18

that is the solution I'm using:

mViewPager : is the view you are using to set you Fragment

mViewPager = (YourViewPager) findViewById(R.id.myPager);

TABLE : is just a Integer list of the position of all my Fragments

    public void destroyAllItem() {
        int mPosition = mViewPager.getCurrentItem();
        int mPositionMax = mViewPager.getCurrentItem()+1;
        if (TABLE.size() > 0 && mPosition < TABLE.size()) {
            if (mPosition > 0) {
                mPosition--;
            }

            for (int i = mPosition; i < mPositionMax; i++) {
                try {
                    Object objectobject = this.instantiateItem(mViewPager, TABLE.get(i).intValue());
                    if (objectobject != null)
                        destroyItem(mViewPager, TABLE.get(i).intValue(), objectobject);
                } catch (Exception e) {
                    Log.i(TAG, "no more Fragment in FragmentPagerAdapter");
                }
            }
        }
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);

        if (position <= getCount()) {
            FragmentManager manager = ((Fragment) object).getFragmentManager();
            FragmentTransaction trans = manager.beginTransaction();
            trans.remove((Fragment) object);
            trans.commit();
        }
    }
MPelletier
  • 16,256
  • 15
  • 86
  • 137
douarbou
  • 2,283
  • 1
  • 21
  • 25
16

First, I suggest that you consider altering your FragmentPagerAdapter, to look more like the sample. You normally do not hold a list of fragments, any more than an ArrayAdapter normally holds a list of Views for the rows. Normally, you create the fragments on demand, and somebody else holds the list.

Then, to delete something, delete it from your model data (what the FragmentPagerAdapter normally wraps). Make sure that getCount() will then return the right number of items. Then, call notifyDataSetChanged() on the FragmentPagerAdapter, which should trigger a redraw of the ViewPager.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • OK thanks so far! Trying to get my code like in the example. In my code I go through a Object-List and fill the Fragment List with the proper Fragments (Image, Audio, Video). `for (int i = 0; i < wiList.size(); i++) { WhiteboardMedia tmpWi = wiList.get(i); if (tmpWi.getType() == IMAGE) { fragments.add(IMAGE); } else if () { fragments.add(AUDIO); } else if () { fragments.add(VIDEO); } } mAdapter = new MPagerAdapter(getSupportFragmentManager(), fragments);` Where do I have to place this code? In the example it looks like the Fragments are all the same type. – Dominik Mar 19 '12 at 08:55
  • 1
    @user753827: `getItem()` would need to have the smarts to return the right fragment. – CommonsWare Mar 19 '12 at 09:59
  • 2
    Ugh, I've been having the same problem for ages. The fragments don't get collected and stay there visually (in their old and wrong position) until I scroll too far right/left and the system culls them and resyncs. Any idea what I'm doing wrong? My code looks pretty much like the example. – Stavros Korokithakis Jun 20 '13 at 03:23
  • 2
    @StavrosKorokithakis: Adding and removing fragments was sufficient of a pain that I eventually wrote `ArrayPagerAdapter` to try to provide a better solution: https://github.com/commonsguy/cwac-pager It's still early days for the component, but it holds promise. – CommonsWare Jun 20 '13 at 11:06
  • 1
    @CommonsWare Oh that looks fantastic, thank you! I just got the `FragmentPagerAdapter` working (needed a `FragmentStatePager` in the end, the vanilla `FragmentPagerAdapter` doesn't like removing fragments), but I'll use your component next time, thank you! – Stavros Korokithakis Jun 20 '13 at 17:46
  • @CommonsWare thank you for your component! if we want to have some animation only for removing fragment how can we achieve that? – Swapnil Kadam Nov 04 '16 at 18:02
  • @Swapnil: I have no idea, other than that it probably has nothing to do with the library. – CommonsWare Nov 04 '16 at 23:01
  • @CommonsWare true it has nothing to do with the library. Thanks for awesome library :) – Swapnil Kadam Nov 05 '16 at 01:52
  • Just in case anyone needs this functionality, please follow the following steps 1)get current fragment displayed in viewpager using adapter.getCurrentFragment(); 2)get fragments view (View v = currentFragment.getView();) 3)use animation listener on the view and in onAnimationEnd() use adapter.remove(mPager.getCurrentItem()); – Swapnil Kadam Nov 05 '16 at 03:52
1

I found a solution ovverriding the method "onPostResume()" of the activity and calling the notifyDataSetChanged inside that.

@Override
protected void onPostResume() {
    super.onPostResume();
    if(this.mCustomPagerAdapter!=null){
        this.mCustomPagerAdapter.notifyDataSetChanged();
    }
}
1

If you are using FragmentPagerAdapter for adding and removing fragments at random position(not always at the end) dynamically, there is a method you need to taken more attention which is getItemId. By default, FragmentPagerAdapter uses position combines viewId as the tag name for fragments, however the position changes if you add or remove fragments. As a result, you may get an empty page because the position you are adding is occupied by an existing fragment. To solved this problem, override getItemId.

@Override
public long getItemId(int position) {
    long itemId = ...;  //Provide your unique ID here according to you logic
    return itemId;
}
Jason
  • 46
  • 5
  • After getting the itemId do I have to manually remove each Item from the FragmentPagerAdapter? Is there any other way to automatically update FragmentPagerAdapter based on the Model data? – Slick Slime Jun 22 '18 at 12:56
  • What you need to do is call the notifyDatasetChanged on the adapter after adding or removing fragments. Not sure this answers your "automatically" question. – Jason Jun 26 '18 at 17:47
0

In my case, when i try to remove one item from the adapter, i will do as follow:

// get the position of item to remove
int position = getBinding().vp.getCurrentItem();
// remove the item from adapter
adapter.removeItem(position);
adapter.notifyDataSetChanged();
// minus one from the count
totalInvoice--;
updateTitle(getBinding().vp.getCurrentItem());
if (totalInvoice == 0) {
    finish();
}
// set the adapter to view pager again            
getBinding().vp.setAdapter(adapter);
// smooth scroll to given position
getBinding().vp.setCurrentItem(position);

The reason that i did above is that i find that even though you removed one from the data list, but the view of fragment still exist. So you have to let the view pager instantiate the view of given position. The answer above which trying to remove all fragments doesn't work for me. So, I find out the poor way of setting adapter to view pager again.

Shawn Wong
  • 554
  • 6
  • 15