动态地添加/删除ViewPager页面

59

我想动态地添加或删除我的视图翻页器中的页面,这是否可能?


@Sam_k 还没有。我还没时间试一下。Paresh提供的解决方案不起作用,但是Zsombor的可能有效。如果我找到什么,我会告诉你的。 - Arnab Chakraborty
请参考这个答案 - Hai nguyen thanh
9个回答

26
是的,您可以动态地向提供视图的PagerAdapter中添加或删除视图,并从PagerAdapter中调用notifyDataSetChanged()来告知受影响的ViewPager有关更改的信息。但是,当您这样做时,必须重写PagerAdapter的getItemPosition(Object)方法,以告诉它们当前正在显示的项目是否已经改变了位置。默认情况下,此函数设置为POSITION_UNCHANGED,因此如果不重写此方法,则ViewPager将不会立即刷新。例如:
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;
        }
    }
}

如果您只是想暂时将视图添加或删除显示,而不从PagerAdapter的数据集中删除,可以尝试使用setPrimaryItem(ViewGroup, int, Object)来访问PagerAdapter数据中的特定视图,以及destroyItem(ViewGroup, int, Object)来从显示中移除视图。


重写getItemPosition帮助我解决了一个困扰我一周多的bug。非常感谢您。 - Russ Wheeler
1
在getItemPosition中的if语句后面,您丢失了闭合括号。 - Yazon2006
@Yazon2006 我不这么认为。它与else关键字在同一行。也许你错过了? - CodePro_NotYet
@CodePro_NotYet 是的,也许你是对的!感谢你的再次确认! - Yazon2006
这个将视图转换为我的特定片段是否有效,还是我必须将其转换为我的特定片段? - bh_earth0

18

是的,由于ViewPager从PagerAdapter获取子视图,因此您可以在其中添加/删除新页面,并调用.notifyDataSetChanged()重新加载它。


62
理论上你的答案是正确的,但在实际应用中,从ViewPager中删除和添加内容是很麻烦的,特别是涉及到Fragment时更是如此。 - Guilherme Oliveira
2
您应该在适配器中重写getItemPosition()方法。 - Davide
@GuilhermeOliveira 我在索引1处插入了一个视图并调用了notifyDatasetChanged。但是ViewPager没有刷新所有视图,而是初始化了最后一个索引。你知道如何解决吗? - Allen Vork
实际上,您可以很容易地在当前位置(ViewPager的右侧)之后添加片段。但是,如果您想在当前位置之前(即ViewPager的左侧)添加而不跳转到它...那就真的很棘手了。我花了两天时间去研究,但仍然不知道如何做到这一点。 - Zoltan Szilagyi
调用 notifyDataSetChange 后,页面变成空白,并且视图被重新实例化。如果我从视图页适配器中删除视图,该怎么办?我尝试使用 getItemPosition(),但它不起作用。请提供任何建议。谢谢。 - Ritesh Adulkar

16
是的,代码应该像这样:
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;
        }
    }

但是有一个bug,如果当前的项目是0,并且要删除页面0,它不会立即刷新屏幕,我还没有找到解决方案。


1
mListViews来自哪里? - Muz
1
从代码上看,mListViews 应该是 myPagerAdapter 类中继承了 FragmentPagerAdapter 的 View 列表,因为那是存储 ViewPager mPager 所有视图(页面)的理想区域。 - StrikeForceZero
6
@tc007733,这不是一个 bug,你需要重写 getItemPosition(Object o) 方法,如果这个方法已经失效了,就返回 POSITION_NONE。 - DayDayHappy

4

以下是这个问题的另一种解决方案。我的适配器:

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

动态删除和添加代码

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

pagerAdapter.addPage(pass your fragment);

根据Peri Hartman的建议,我将ViewPager适配器设置为null,并在删除视图后再次放置适配器,这样它开始工作了。 在此之前,第0页没有显示其列表内容。

非常感谢!这是一件很困难的事情。 - Kevin van Mierlo
vp是什么,在哪里初始化的? - ManishSB

3
我相信你已经通过扩展PageAdapter创建了一个适配器,因此有一个方法:
 @Override
 public void destroyItem(View collection, int position, Object view) {
           ((ViewPager) collection).removeView((View) view);
 }

有关详细示例,请查看此示例

它从容器中销毁项目。我想永久从我的应用程序中删除。 - sam_k
@Parash 如果你明白我的意思,请回复我。 - sam_k
链接已损坏,你能修复一下吗? - Yuchen

2

首先:重写pagerAdapter方法“getItemPosition”

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

第二步:解除与适配器的数据绑定,然后调用adapter.notifydatachanged。

虽然这个解决方案可行,但我听说它非常浪费内存。 - martyglaubitz

1
@Bind(R.id.pager)
ViewPager pager;
int pos = pager.getCurrentItem();
pager.removeViewAt(pos);

3
虽然这段代码片段可能解决问题,但包括解释真的有助于提高您帖子的质量。请记住,您正在回答未来读者的问题,而这些人可能不了解您提出代码建议的原因。 - yennsarah

0

根据其他答案和资源,我最终得到了这段代码。

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

}

主活动:

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

}

删除页面:

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 的代码与此相同。

布局是使用 android.support.v4.view.ViewPager 和 id 为 container 的 Fragment,以及 id 为 section_labelTextView 的简单 ViewPager/Fragment 布局。

资源:


0

你需要再次将适配器设置为ViewPager,这样它才会刷新内容。

在我的PagerAdaper中使用removeView(int pos)

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

无论我在哪里删除文件,都必须这样做

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

编辑:

以下方法是有效的,您可以应用以下方法。

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

用你的上下文替换YOUR_CONTEXT,用你的内容名称替换你的内容,例如更新列表或其他内容。

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