【问题标题】:How to Remove Fragment from FragmentPagerAdapter?如何从 FragmentPagerAdapter 中删除片段?
【发布时间】:2012-04-03 06:24:43
【问题描述】:

我知道这里已经有一些关于此的主题,但我找不到可以为我的案例工作的解决方案。

我有一个使用自定义 FragmentActivityFragmentPagerAdapter 的滑动图库,其中包含片段列表。

FragmentActivity 中有一个ImageView“删除”。如果单击,则调用函数deleteMedia(),然后应删除当前的Fragment,并应显示以下Fragment。 在我的示例中,我必须如何做到这一点?

片段活动:

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

感谢您的帮助!

【问题讨论】:

    标签: android android-fragments fragmentpageradapter android-fragmentactivity


    【解决方案1】:

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

    mViewPager : 是你用来设置 Fragment 的视图

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

    【讨论】:

    • 完美的杜阿布!谢谢!
    • 像魅力一样工作!节省了我的时间!谢谢你:)
    • 我正在尝试根据位置删除选定的片段,因为此代码视图已被删除,但仍显示空白片段。如何去除碎片?
    • @scienticious 你有解决方法来删除空白片段吗?
    【解决方案2】:

    首先,我建议您考虑更改您的FragmentPagerAdapter,使其看起来更像the sample。您通常不保存片段列表,就像ArrayAdapter 通常保存行的Views 列表一样。通常,您根据需要创建片段,而其他人持有该列表。

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

    【讨论】:

    • 好的,谢谢!试图像示例中那样获取我的代码。在我的代码中,我通过一个对象列表并用正确的片段(图像、音频、视频)填充片段列表。 for (int i = 0; i &lt; 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);我必须在哪里放置此代码?在示例中,片段看起来都是相同的类型。
    • @user753827: getItem() 需要聪明才能返回正确的片段。
    • 呃,我多年来一直遇到同样的问题。碎片不会被收集并在视觉上停留在那里(在它们旧的和错误的位置),直到我向右/向左滚动太远并且系统剔除它们并重新同步。知道我做错了什么吗?我的代码看起来很像示例。
    • @StavrosKorokithakis:添加和删除片段已经足够痛苦了,我最终写了ArrayPagerAdapter 以尝试提供更好的解决方案:github.com/commonsguy/cwac-pager 该组件还处于早期阶段,但它有希望.
    • @CommonsWare 哦,看起来棒极了,谢谢!我刚刚让FragmentPagerAdapter 工作(最后需要FragmentStatePager,香草FragmentPagerAdapter 不喜欢删除片段),但我下次会使用你的组件,谢谢!
    【解决方案3】:

    我找到了一个解决方案,覆盖了活动的“onPostResume()”方法并在其中调用了 notifyDataSetChanged。

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

    【讨论】:

      【解决方案4】:

      如果您使用 FragmentPagerAdapter 在随机位置(并非总是在末尾)动态添加和删除片段,则需要更多注意的方法是 getItemId。默认情况下,FragmentPagerAdapter 使用位置组合 viewId 作为片段的标签名称,但是如果添加或删除片段,位置会发生变化。结果,您可能会得到一个空白页面,因为您要添加的位置已被现有片段占用。要解决此问题,请覆盖 getItemId。

      @Override
      public long getItemId(int position) {
          long itemId = ...;  //Provide your unique ID here according to you logic
          return itemId;
      }
      

      【讨论】:

      • 获得 itemId 后,我是否必须手动从 FragmentPagerAdapter 中删除每个项目?有没有其他方法可以根据 Model 数据自动更新 FragmentPagerAdapter?
      • 添加或删除片段后,您需要在适配器上调用 notifyDatasetChanged。不确定这是否能回答您的“自动”问题。
      【解决方案5】:

      就我而言,当我尝试从适配器中删除一项时,我将执行以下操作:

      // 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);
      

      我上面做的原因是我发现即使你从数据列表中删除了一个,但片段的视图仍然存在。所以你必须让视图寻呼机实例化给定位置的视图。上面试图删除所有片段的答案对我不起作用。所以,我发现了设置适配器以再次查看寻呼机的糟糕方法。

      【讨论】:

        猜你喜欢
        • 2013-12-03
        • 1970-01-01
        • 2018-10-13
        • 1970-01-01
        • 1970-01-01
        • 2013-09-13
        • 1970-01-01
        • 2015-10-01
        • 1970-01-01
        相关资源
        最近更新 更多