Добавить / удалить страницы в ViewPager динамически - PullRequest
55 голосов
/ 09 ноября 2011

Я хочу динамически добавлять или удалять страницы из моего пейджера. Это возможно?

Ответы [ 9 ]

26 голосов
/ 28 мая 2014

Да. Вы можете динамически добавлять или удалять представления в PagerAdapter, который их передает ViewPager, и вызывать notifyDataSetChanged() из PagerAdapter, чтобы предупредить об этом затронутый ViewPager. Тем не менее, когда вы делаете это, вы должны переопределить getItemPosition(Object) PagerAdapter, который сообщает им, изменились ли позиции, которые они показывают в данный момент. По умолчанию эта функция установлена ​​на 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) для удаления вид с дисплея.

18 голосов
/ 09 ноября 2011

Да, поскольку ViewPager получает дочерние представления от PagerAdapter, вы можете добавить новые страницы / удалить страницы и вызвать .notifyDataSetChanged (), чтобы перезагрузить его.

16 голосов
/ 09 апреля 2012

Да, код должен быть таким:

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

Но есть ошибка. Если текущий элемент равен 0, и для удаления страницы 0 он не обновит экран мгновенно, я не нашел решения для этого.

3 голосов
/ 06 мая 2013

Вот альтернативное решение этого вопроса. Мой адаптер:

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

По совету Пери Хартман он начал работать после того, как я установил null для адаптера ViewPager и снова вставил адаптер после удаления представлений. До этого на странице 0 не отображалось содержимое списка.

3 голосов
/ 09 ноября 2011

Я уверен, что вы создали адаптер, расширив PageAdapter, поэтому есть один метод:

 @Override
 public void destroyItem(View collection, int position, Object view) {
           ((ViewPager) collection).removeView((View) view);
 }

Для подробного примера того же самого, просто просмотрите этот пример .

2 голосов
/ 12 мая 2015

Первое: переопределить метод pagerAdapter "getItemPosition"

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

Второе: удалить привязку данных с помощью adapter.and и вызвать adapter.notifydatachanged

1 голос
/ 08 декабря 2016
@Bind(R.id.pager)
ViewPager pager;
int pos = pager.getCurrentItem();
pager.removeViewAt(pos);
0 голосов
/ 13 января 2018

На основании других ответов и других ресурсов, которые я закончил с этим кодом.

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

}

MainActivity :

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 имеет тот же код.

Макеты - это простые макеты ViewPager / Fragment с android.support.v4.view.ViewPager с идентификатором container и Fragment TextView с идентификатором section_label.

Ресурсы:

0 голосов
/ 25 октября 2017

Это решение пока хорошо работает:

 public class CustomPagerAdapter extends PagerAdapter {

    private final List<Item> objects = new ArrayList<>();

    public CustomPagerAdapter(List<Item> objects) {
        if (objects != null) {
            this.objects.add(objects);
        }
    }

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

    @Override
    public boolean isViewFromObject(View view, Object object) {
        Item item = (Item) object;
        ItemView itemView = (ItemView) view;
        return Objects.equals(itemView.getItem(), item);
    }

    @Override
    public int getItemPosition(Object object) {
        Item item = (Item) object;
        int idx = objects.indexOf(item);
        return idx == -1 ? POSITION_NONE : idx;
    }

    @Override
    public Item instantiateItem(ViewGroup container, int position) {
        Item item = objects.get(position);

        final int id = generateViewIdForItem(item);
        ItemView itemView = new ItemView(container.getContext());
        itemView.setId(id);
        container.addView(itemView);

        itemView.setItem(item);

        return item;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Item item = (Item) object;
        final int id = generateViewIdForItem(item);
        View view = container.findViewById(id);
        if (view != null) {
            container.removeView(view);
        }
    }

    public void update(@Nullable List<Item> objects) {
        this.objects.clear();
        if (objects != null) {
            this.objects.addAll(objects);
        }
        notifyDataSetChanged();
    }

    public void clear() {
        update(null);
    }

    /* add remove/update/add methods if you need, don't forget to call notifyDataSetChanged */

    private static int generateViewIdForItem(Item item) {
        return Math.abs(item.hashCode());
    }
}

Обратите внимание:

  • Ваш класс Item должен содержать соответствующую реализацию для equals и hashCode методов
  • Ваш класс ItemView должен содержать геттер и сеттер для вашего Item объекта.
...