如何从FragmentPagerAdapter中移除Fragment?

11

我知道这里已经有一些关于这个问题的主题了,但是我找不到一个解决方案可以适用于我的情况。

我有一个使用自定义FragmentActivityFragmentPagerAdapter的工作中的滑动画廊,其中包含一个片段列表。

FragmentActivity内部有一个名为“delete”的ImageView。如果单击它,则会调用deleteMedia()函数,然后应该删除当前Fragment并显示下一个Fragment。在我的例子中,我该怎么做呢?

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();
}
}

感谢您的帮助!

5个回答

18

这是我正在使用的解决方案:

mViewPager:是您用于设置片段的视图。

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

TABLE:只是我所有碎片的位置的整数列表。

    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();
        }
    }

完美的 Douarbou!谢谢! - anthony
非常好用!节省了我的时间!谢谢 :) - Vivek Solanki
我正在尝试根据位置删除所选片段,因此代码视图被删除,但仍显示一个空白片段。 如何删除该片段? - scienticious
@scienticious 你解决了删除空白片段的问题吗? - Anupriya

16

首先,建议您考虑修改您的FragmentPagerAdapter,使其更像示例。通常情况下,您不会持有片段列表,就像ArrayAdapter通常不会持有行的Views列表一样。通常情况下,您会按需创建片段,而其他人则持有列表。

然后,要删除某些内容,请从您的模型数据(FragmentPagerAdapter通常包装的内容)中删除它。确保getCount()将返回正确的项目数。接着,在FragmentPagerAdapter上调用notifyDataSetChanged(),这应该会触发ViewPager的重绘。


好的,谢谢你到目前为止所做的工作!我正在尝试让我的代码像示例中一样。在我的代码中,我遍历一个对象列表,并使用适当的片段(图像、音频、视频)填充片段列表。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);我应该把这段代码放在哪里?在示例中,看起来片段都是相同类型的。 - Dominik
1
@user753827:getItem()需要具备智能返回正确片段的能力。 - CommonsWare
2
天啊,我已经遇到同样的问题很久了。这些片段没有被收集起来,而是停留在原来错误的位置上,直到我向右/向左滚动得太远,系统才会将它们剔除并重新同步。你有什么想法,我是哪里做错了吗?我的代码看起来几乎和示例一样。 - Stavros Korokithakis
2
@StavrosKorokithakis:添加和删除片段非常麻烦,所以我最终编写了ArrayPagerAdapter来尝试提供更好的解决方案:https://github.com/commonsguy/cwac-pager。该组件仍处于早期阶段,但它具有很大的潜力。 - CommonsWare
1
@CommonsWare 哦,那看起来太棒了,谢谢!我刚刚让 FragmentPagerAdapter 工作起来了(最后需要一个 FragmentStatePager,因为原始的 FragmentPagerAdapter 不喜欢删除片段),但下次我会使用您的组件,谢谢! - Stavros Korokithakis
显示剩余4条评论

1
我找到了一个解决方案,覆盖活动的“onPostResume()”方法,并在其中调用notifyDataSetChanged。
@Override
protected void onPostResume() {
    super.onPostResume();
    if(this.mCustomPagerAdapter!=null){
        this.mCustomPagerAdapter.notifyDataSetChanged();
    }
}

1
如果您正在动态地在随机位置(并非总是在末尾)添加和删除片段,使用FragmentPagerAdapter,则需要注意一个方法,即getItemId。默认情况下,FragmentPagerAdapter使用position结合viewId作为片段的标记名称,但是如果添加或删除片段,则position会发生变化。结果,您可能会得到一个空页面,因为您要添加的位置被现有片段占用。为解决此问题,请覆盖getItemId方法。
@Override
public long getItemId(int position) {
    long itemId = ...;  //Provide your unique ID here according to you logic
    return itemId;
}

获取itemId后,我是否需要手动从FragmentPagerAdapter中删除每个Item?是否有其他方法可以根据模型数据自动更新FragmentPagerAdapter? - Slick Slime
你需要在添加或删除片段后,在适配器上调用notifyDatasetChanged。不确定这是否回答了你的“自动”问题。 - Jason

0
在我的情况下,当我尝试从适配器中移除一个项目时,我会按照以下步骤进行:
// 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);

我这样做的原因是,尽管你从数据列表中删除了一个,但片段的视图仍然存在。因此,你必须让视图页实例化给定位置的视图。上面试图删除所有片段的答案对我不起作用。所以,我找到了重新设置适配器到视图页的可怜方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接