Я пытаюсь динамически добавлять и удалять фрагменты из ViewPager, добавление работает без проблем, но удаление работает не так, как ожидалось.
Каждый раз, когда я хочу удалить текущий элемент, удаляется последний.
Я также пробовал использовать FragmentStatePagerAdapter или вернуть POSITION_NONE в методе адаптера getItemPosition.
Что я делаю не так?
Вот простой пример:
MainActivity.java
public class MainActivity extends FragmentActivity implements TextProvider {
private Button mAdd;
private Button mRemove;
private ViewPager mPager;
private MyPagerAdapter mAdapter;
private ArrayList<String> mEntries = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mEntries.add("pos 1");
mEntries.add("pos 2");
mEntries.add("pos 3");
mEntries.add("pos 4");
mEntries.add("pos 5");
mAdd = (Button) findViewById(R.id.add);
mRemove = (Button) findViewById(R.id.remove);
mPager = (ViewPager) findViewById(R.id.pager);
mAdd.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
addNewItem();
}
});
mRemove.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
removeCurrentItem();
}
});
mAdapter = new MyPagerAdapter(this.getSupportFragmentManager(), this);
mPager.setAdapter(mAdapter);
}
private void addNewItem() {
mEntries.add("new item");
mAdapter.notifyDataSetChanged();
}
private void removeCurrentItem() {
int position = mPager.getCurrentItem();
mEntries.remove(position);
mAdapter.notifyDataSetChanged();
}
@Override
public String getTextForPosition(int position) {
return mEntries.get(position);
}
@Override
public int getCount() {
return mEntries.size();
}
private class MyPagerAdapter extends FragmentPagerAdapter {
private TextProvider mProvider;
public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
super(fm);
this.mProvider = provider;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mProvider.getTextForPosition(position));
}
@Override
public int getCount() {
return mProvider.getCount();
}
}
}
TextProvider.java
public interface TextProvider {
public String getTextForPosition(int position);
public int getCount();
}
MyFragment.java
public class MyFragment extends Fragment {
private String mText;
public static MyFragment newInstance(String text) {
MyFragment f = new MyFragment(text);
return f;
}
public MyFragment() {
}
public MyFragment(String text) {
this.mText = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment, container, false);
((TextView) root.findViewById(R.id.position)).setText(mText);
return root;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="add new item" />
<Button
android:id="@+id/remove"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="remove current item" />
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
</LinearLayout>
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/position"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="35sp" />
</LinearLayout>
MyFragment.java
??Ответы:
Решения Лауса было недостаточно, чтобы заставить все работать для меня, поскольку существующие фрагменты не разрушались. Мотивированный этим ответом я обнаружил, что решение состоит в том, чтобы переопределить
getItemId(int position)
методFragmentPagerAdapter
предоставления нового уникального идентификатора всякий раз, когда произошло изменение ожидаемого положения фрагмента.Исходный код:
private class MyPagerAdapter extends FragmentPagerAdapter { private TextProvider mProvider; private long baseId = 0; public MyPagerAdapter(FragmentManager fm, TextProvider provider) { super(fm); this.mProvider = provider; } @Override public Fragment getItem(int position) { return MyFragment.newInstance(mProvider.getTextForPosition(position)); } @Override public int getCount() { return mProvider.getCount(); } //this is called when notifyDataSetChanged() is called @Override public int getItemPosition(Object object) { // refresh all fragments when data set changed return PagerAdapter.POSITION_NONE; } @Override public long getItemId(int position) { // give an ID different from position when position has been changed return baseId + position; } /** * Notify that the position of a fragment has been changed. * Create a new ID for each position to force recreation of the fragment * @param n number of items which have been changed */ public void notifyChangeInPosition(int n) { // shift the ID returned by getItemId outside the range of all previous fragments baseId += getCount() + n; } }
Теперь, например, если вы удалите одну вкладку или измените порядок, вы должны позвонить
notifyChangeInPosition(1)
перед вызовомnotifyDataSetChanged()
, что обеспечит воссоздание всех фрагментов.Почему это решение работает
Переопределение getItemPosition ():
Когда
notifyDataSetChanged()
вызывается, адаптер вызываетnotifyChanged()
метод, кViewPager
которому он подключен. ВViewPager
то проверяет значение , возвращенное в адаптереgetItemPosition()
для каждого элемента, удаляя те элементы , которые возвращаютPOSITION_NONE
(см исходного кода ) , а затем репопулирующие.Переопределение getItemId ():
Это необходимо, чтобы предотвратить перезагрузку адаптера старого фрагмента при
ViewPager
повторном заполнении. Вы можете легко понять, почему это работает, посмотрев исходный код instantiateItem () вFragmentPagerAdapter
.final long itemId = getItemId(position); // Do we already have this fragment? String name = makeFragmentName(container.getId(), itemId); Fragment fragment = mFragmentManager.findFragmentByTag(name); if (fragment != null) { if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); mCurTransaction.attach(fragment); } else { fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId)); }
Как видите,
getItem()
метод вызывается только в том случае, если диспетчер фрагментов не находит существующих фрагментов с тем же идентификатором. Мне кажется ошибкой, что старые фрагменты все еще прикреплены даже послеnotifyDataSetChanged()
вызова, но в документацииViewPager
четко указано , что:Так что, надеюсь, описанный здесь обходной путь не понадобится в будущей версии библиотеки поддержки.
источник
notifyDataSetChanged()
работать.ViewPager не удаляет ваши фрагменты с помощью приведенного выше кода, потому что он загружает несколько представлений (или фрагментов в вашем случае) в память. В дополнение к видимому виду он также загружает вид по обе стороны от видимого. Это обеспечивает плавную прокрутку от представления к представлению, что делает ViewPager таким крутым.
Чтобы добиться желаемого эффекта, вам нужно сделать пару вещей.
Измените FragmentPagerAdapter на FragmentStatePagerAdapter. Причина этого в том, что FragmentPagerAdapter навсегда сохранит все представления, загружаемые в память. Где FragmentStatePagerAdapter удаляет представления, выходящие за рамки текущих и доступных для просмотра представлений.
Переопределите метод адаптера getItemPosition (показано ниже). Когда мы вызываем
mAdapter.notifyDataSetChanged();
ViewPager, он опрашивает адаптер, чтобы определить, что изменилось с точки зрения позиционирования. Мы используем этот метод, чтобы сказать, что все изменилось, поэтому повторно обработайте все ваше позиционирование вида.А вот код ...
private class MyPagerAdapter extends FragmentStatePagerAdapter { //... your existing code @Override public int getItemPosition(Object object){ return PagerAdapter.POSITION_NONE; } }
источник
мое рабочее решение для удаления страницы фрагмента из пейджера просмотра
public class MyFragmentAdapter extends FragmentStatePagerAdapter { private ArrayList<ItemFragment> pages; public MyFragmentAdapter(FragmentManager fragmentManager, ArrayList<ItemFragment> pages) { super(fragmentManager); this.pages = pages; } @Override public Fragment getItem(int index) { return pages.get(index); } @Override public int getCount() { return pages.size(); } @Override public int getItemPosition(Object object) { int index = pages.indexOf (object); if (index == -1) return POSITION_NONE; else return index; } }
И когда мне нужно удалить какую-то страницу по индексу, я делаю это
pages.remove(position); // ArrayList<ItemFragment> adapter.notifyDataSetChanged(); // MyFragmentAdapter
Вот и инициализация моего адаптера
MyFragmentAdapter adapter = new MyFragmentAdapter(getSupportFragmentManager(), pages); viewPager.setAdapter(adapter);
источник
Фрагмент уже должен быть удален, но проблема заключалась в состоянии сохранения окна просмотра.
Пытаться
myViewPager.setSaveFromParentEnabled(false);
Ничего не сработало, но это решило проблему!
Ура!
источник
У меня была идея просто скопировать исходный код из
android.support.v4.app.FragmentPagerAdpater
пользовательского класса с именемCustumFragmentPagerAdapter
. Это дало мне возможность изменитьinstantiateItem(...)
так, чтобы каждый раз, когда он вызывается, он удаляет / уничтожает прикрепленный в данный момент фрагмент, прежде чем добавить новый фрагмент, полученный изgetItem()
метода.Просто измените
instantiateItem(...)
следующим образом:@Override public Object instantiateItem(ViewGroup container, int position) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } final long itemId = getItemId(position); // Do we already have this fragment? String name = makeFragmentName(container.getId(), itemId); Fragment fragment = mFragmentManager.findFragmentByTag(name); // remove / destroy current fragment if (fragment != null) { mCurTransaction.remove(fragment); } // get new fragment and add it fragment = getItem(position); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId)); if (fragment != mCurrentPrimaryItem) { fragment.setMenuVisibility(false); fragment.setUserVisibleHint(false); } return fragment; }
источник
Вы можете лучше сочетать и то, и другое:
private class MyPagerAdapter extends FragmentStatePagerAdapter { //... your existing code @Override public int getItemPosition(Object object){ if(Any_Reason_You_WantTo_Update_Positions) //this includes deleting or adding pages return PagerAdapter.POSITION_NONE; } else return PagerAdapter.POSITION_UNCHANGED; //this ensures high performance in other operations such as editing list items. }
источник
Для будущих читателей!
Теперь вы можете использовать ViewPager2 для динамического добавления и удаления фрагмента из окна просмотра.
Справочник по API формы цитирования
Посмотрите
MutableCollectionFragmentActivity.kt
в googlesample / android-viewpager2 пример динамического добавления и удаления фрагментов из окна просмотра.Довожу до вашего сведения:
Статьи:
Справочник по API
Примечания к выпуску
Репозиторий образцов: https://github.com/googlesamples/android-viewpager2
источник
Ответ Лауса работает нормально. Но я не думаю, что всегда возвращать POSITION_NONE - хорошая идея. Потому что POSITION_NONE означает, что фрагмент должен быть уничтожен и будет создан новый фрагмент. Вы можете проверить это в функции dataSetChanged в исходном коде ViewPager.
if (newPos == PagerAdapter.POSITION_NONE) { mItems.remove(i); i--; ... not related code mAdapter.destroyItem(this, ii.position, ii.object);
Так что я думаю, вам лучше использовать arrayylist weakReference, чтобы сохранить все созданные вами фрагменты. А когда вы добавляете или удаляете какую-то страницу, вы можете получить нужную позицию из своего собственного Arraylist.
public int getItemPosition(Object object) { for (int i = 0; i < mFragmentsReferences.size(); i ++) { WeakReference<Fragment> reference = mFragmentsReferences.get(i); if (reference != null && reference.get() != null) { Fragment fragment = reference.get(); if (fragment == object) { return i; } } } return POSITION_NONE; }
Согласно комментариям, getItemPosition вызывается, когда ведущее представление пытается определить, изменилась ли позиция элемента. А возвращаемое значение означает его новую позицию.
Но этого недостаточно. Нам еще предстоит сделать важный шаг. В исходном коде FragmentStatePagerAdapter есть массив с именем «mFragments», кэширующий фрагменты, которые не уничтожаются. И в функции instantiateItem.
if (mFragments.size() > position) { Fragment f = mFragments.get(position); if (f != null) { return f; } }
Он вернул кэшированный фрагмент напрямую, когда обнаружил, что кешированный фрагмент не равен нулю. Итак, есть проблема. Из примера, давайте удалим одну страницу в позиции 2. Во-первых, мы удалим этот фрагмент из нашего собственного ссылочного массива. поэтому в getItemPosition он вернет POSITION_NONE для этого фрагмента, а затем этот фрагмент будет уничтожен и удален из "mFragments".
mFragments.set(position, null);
Теперь фрагмент в позиции 3 будет в позиции 2. И будет вызван instantiatedItem с параметром позиции 3. В настоящее время третий элемент в «mFramgents» не равен нулю, поэтому он вернется напрямую. Но на самом деле он вернул фрагмент в позиции 2. Итак, когда мы перейдем на страницу 3, мы найдем там пустую страницу.
Чтобы обойти эту проблему. Я советую вам скопировать исходный код FragmentStatePagerAdapter в свой собственный проект, а когда вы добавляете или удаляете операции, вы должны добавлять и удалять элементы в массиве «mFragments».
Все будет проще, если вы просто используете PagerAdapter вместо FragmentStatePagerAdapter. Удачи.
источник
private void setupViewPager(ViewPager viewPager) { ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFrag(new fragmnet1(), "HOME"); adapter.addFrag(new fragmnet2(), "SERVICES"); viewPager.setAdapter(adapter); } private void setupViewPagerCustom(ViewPager viewPager) { ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFrag(new fragmnet3(), "Contact us"); adapter.addFrag(new fragmnet4(), "ABOUT US"); viewPager.setAdapter(adapter); } //Viewpageradapter, handles the views static class ViewPagerAdapter extends FragmentStatePagerAdapter { private final List<Fragment> mFragmentList = new ArrayList<>(); private final List<String> mFragmentTitleList = new ArrayList<>(); public ViewPagerAdapter(FragmentManager manager){ super(manager); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } @Override public int getItemPosition(Object object){ return PagerAdapter.POSITION_NONE; } public void addFrag(Fragment fragment, String title){ mFragmentList.add(fragment); mFragmentTitleList.add(title); } @Override public CharSequence getPageTitle(int position){ return mFragmentTitleList.get(position); } }
источник
У меня были проблемы с
FragmentStatePagerAdapter
. После удаления предмета:После множества экспериментов я пришел к следующему решению.
public class SomeAdapter extends FragmentStatePagerAdapter { private List<Item> items = new ArrayList<Item>(); private boolean removing; @Override public Fragment getItem(int position) { ItemFragment fragment = new ItemFragment(); Bundle args = new Bundle(); // use items.get(position) to configure fragment fragment.setArguments(args); return fragment; } @Override public int getCount() { return items.size(); } @Override public int getItemPosition(Object object) { if (removing) { return PagerAdapter.POSITION_NONE; } Item item = getItemOfFragment(object); int index = items.indexOf(item); if (index == -1) { return POSITION_NONE; } else { return index; } } public void addItem(Item item) { items.add(item); notifyDataSetChanged(); } public void removeItem(int position) { items.remove(position); removing = true; notifyDataSetChanged(); removing = false; } }
Это решение использует взлом только в случае удаления элемента. В противном случае (например, при добавлении элемента) он сохраняет чистоту и производительность исходного кода.
Конечно, извне адаптера вы вызываете только addItem / removeItem, нет необходимости вызывать notifyDataSetChanged ().
источник
Попробуйте это решение. Я использовал привязку данных для привязки просмотра. Вы можете использовать обычную функцию findViewById ().
public class ActCPExpense extends BaseActivity implements View.OnClickListener, { private static final String TAG = ActCPExpense.class.getSimpleName(); private Context mContext; private ActCpLossBinding mBinding; private ViewPagerAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); try { setContentView(R.layout.act_cp_loss); mBinding = DataBindingUtil.setContentView(this, R.layout.act_cp_loss); mContext = ActCPExpense.this; initViewsAct(); } catch (Exception e) { LogUtils.LOGE(TAG, e); } } private void initViewsAct() { adapter = new ViewPagerAdapter(getSupportFragmentManager()); adapter.addFragment(FragmentCPPayee.newInstance(), "Title"); mBinding.viewpager.setAdapter(adapter); mBinding.tab.setViewPager(mBinding.viewpager); } @Override public boolean onOptionsItemSelected(MenuItem itemActUtility) { int i = itemActUtility.getItemId(); if (i == android.R.id.home) { onBackPressed(); } return super.onOptionsItemSelected(itemActUtility); } @Override public void onClick(View view) { super.onClick(view); int id = view.getId(); if (id == R.id.btnAdd) { addFragment(); } else if (id == R.id.btnDelete) { removeFragment(); } } private void addFragment(){ adapter.addFragment(FragmentCPPayee.newInstance("Title"); adapter.notifyDataSetChanged(); mBinding.tab.setViewPager(mBinding.viewpager); } private void removeFragment(){ adapter.removeItem(mBinding.viewpager.getCurrentItem()); mBinding.tab.setViewPager(mBinding.viewpager); } class ViewPagerAdapter extends FragmentStatePagerAdapter { private final List<Fragment> mFragmentList = new ArrayList<>(); private final List<String> mFragmentTitleList = new ArrayList<>(); public ViewPagerAdapter(FragmentManager manager) { super(manager); } @Override public int getItemPosition(@NonNull Object object) { return PagerAdapter.POSITION_NONE; } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } public void addFragment(Fragment fragment, String title) { mFragmentList.add(fragment); mFragmentTitleList.add(title); } public void removeItem(int pos) { destroyItem(null, pos, mFragmentList.get(pos)); mFragmentList.remove(pos); mFragmentTitleList.remove(pos); adapter.notifyDataSetChanged(); mBinding.viewpager.setCurrentItem(pos - 1, false); } @Override public CharSequence getPageTitle(int position) { return "Title " + String.valueOf(position + 1); } } }
источник
Я добавил функцию clearFragments и использовал эту функцию для очистки адаптера перед установкой новых фрагментов. Это вызывает правильные действия удаления фрагментов. Мой класс pagerAdapter:
private class ChartPagerAdapter extends FragmentPagerAdapter{ private ArrayList<Fragment> fragmentList; ChartPagerAdapter(FragmentManager fm){ super(fm); fragmentList = new ArrayList<>(); } void setFragments(ArrayList<? extends Fragment> fragments){ fragmentList.addAll(fragments); } void clearFragments(){ for(Fragment fragment:fragmentList) getChildFragmentManager().beginTransaction().remove(fragment).commit(); fragmentList.clear(); } @Override public Fragment getItem(int i) { return fragmentList.get(i); } @Override public int getCount() { return fragmentList.size(); } }
источник
я решил эту проблему этими шагами
1- используйте FragmentPagerAdapter
2- в каждом фрагменте создать случайный идентификатор
fragment.id = new Random().nextInt();
3- переопределить getItemPosition в адаптере
@Override public int getItemPosition(@NonNull Object object) { return PagerAdapter.POSITION_NONE; }
4-переопределить getItemId в адаптере
@Override public long getItemId(int position) { return mDatasetFragments.get(position).id; }
5- теперь код удаления
adapter.mDatasetFragments.remove(< item to delete position >); adapter.notifyDataSetChanged();
это сработало для меня, надеюсь, поможет
источник
В моей последней версии кода исправлены ВСЕ ошибки. У меня ушло 3 дня
Обновлено 2020/07/18: Я изменил много исходного кода и исправил так много ошибок, но я не обещаю, что он по-прежнему работает сегодня.
https://github.com/lin1987www/FragmentBuilder/blob/master/commonLibrary/src/main/java/android/support/v4/app/FragmentStatePagerAdapterFix.java
public class FragmentStatePagerAdapterFix extends PagerAdapter { private static final String TAG = FragmentStatePagerAdapterFix.class.getSimpleName(); private static final boolean DEBUG = false; private WeakReference<FragmentActivity> wrFragmentActivity; private WeakReference<Fragment> wrParentFragment; private final FragmentManager mFragmentManager; private FragmentTransaction mCurTransaction = null; protected ArrayList<Fragment> mFragments = new ArrayList<>(); protected ArrayList<FragmentState> mFragmentStates = new ArrayList<>(); protected ArrayList<String> mFragmentTags = new ArrayList<>(); protected ArrayList<String> mFragmentClassNames = new ArrayList<>(); protected ArrayList<Bundle> mFragmentArgs = new ArrayList<>(); private Fragment mCurrentPrimaryItem = null; private boolean[] mTempPositionChange; @Override public int getCount() { return mFragmentClassNames.size(); } public FragmentActivity getFragmentActivity() { return wrFragmentActivity.get(); } public Fragment getParentFragment() { return wrParentFragment.get(); } public FragmentStatePagerAdapterFix(FragmentActivity activity) { mFragmentManager = activity.getSupportFragmentManager(); wrFragmentActivity = new WeakReference<>(activity); wrParentFragment = new WeakReference<>(null); } public FragmentStatePagerAdapterFix(Fragment fragment) { mFragmentManager = fragment.getChildFragmentManager(); wrFragmentActivity = new WeakReference<>(fragment.getActivity()); wrParentFragment = new WeakReference<>(fragment); } public void add(Class<? extends android.support.v4.app.Fragment> fragClass) { add(fragClass, null, null); } public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args) { add(fragClass, args, null); } public void add(Class<? extends android.support.v4.app.Fragment> fragClass, String tag) { add(fragClass, null, tag); } public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args, String tag) { add(fragClass, args, tag, getCount()); } public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args, String tag, int position) { mFragments.add(position, null); mFragmentStates.add(position, null); mFragmentTags.add(position, tag); mFragmentClassNames.add(position, fragClass.getName()); mFragmentArgs.add(position, args); mTempPositionChange = new boolean[getCount()]; } public void remove(int position) { if (position < getCount()) { mTempPositionChange = new boolean[getCount()]; for (int i = position; i < mTempPositionChange.length; i++) { mTempPositionChange[i] = true; } mFragments.remove(position); mFragmentStates.remove(position); mFragmentTags.remove(position); mFragmentClassNames.remove(position); mFragmentArgs.remove(position); } } public void clear(){ mFragments.clear(); mFragmentStates.clear(); mFragmentTags.clear(); mFragmentClassNames.clear(); mFragmentArgs.clear(); } @Override public void startUpdate(ViewGroup container) { } @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment; // If we already have this item instantiated, there is nothing // to do. This can happen when we are restoring the entire pager // from its saved state, where the fragment manager has already // taken care of restoring the fragments we previously had instantiated. fragment = mFragments.get(position); if (fragment != null) { return fragment; } if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } FragmentState fs = mFragmentStates.get(position); if (fs != null) { fragment = fs.instantiate(getFragmentActivity(), getParentFragment()); // Fix bug // http://stackoverflow.com/questions/11381470/classnotfoundexception-when-unmarshalling-android-support-v4-view-viewpagersav if (fragment.mSavedFragmentState != null) { fragment.mSavedFragmentState.setClassLoader(fragment.getClass().getClassLoader()); } } if (fragment == null) { fragment = Fragment.instantiate(getFragmentActivity(), mFragmentClassNames.get(position), mFragmentArgs.get(position)); } if (DEBUG) { Log.v(TAG, "Adding item #" + position + ": f=" + fragment); } fragment.setMenuVisibility(false); fragment.setUserVisibleHint(false); mFragments.set(position, fragment); mFragmentStates.set(position, null); mCurTransaction.add(container.getId(), fragment, mFragmentTags.get(position)); return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { Fragment fragment = (Fragment) object; if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) { Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + ((Fragment) object).getView()); } if (position < getCount()) { FragmentState fragmentState = new FragmentState(fragment); Fragment.SavedState savedState = mFragmentManager.saveFragmentInstanceState(fragment); if (savedState != null) { fragmentState.mSavedFragmentState = savedState.mState; } mFragmentStates.set(position, fragmentState); mFragments.set(position, null); } mCurTransaction.remove(fragment); } @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { Fragment fragment = (Fragment) object; if (fragment != mCurrentPrimaryItem) { if (mCurrentPrimaryItem != null) { mCurrentPrimaryItem.setMenuVisibility(false); mCurrentPrimaryItem.setUserVisibleHint(false); } if (fragment != null) { fragment.setMenuVisibility(true); fragment.setUserVisibleHint(true); } mCurrentPrimaryItem = fragment; } } @Override public void finishUpdate(ViewGroup container) { if (mCurTransaction != null) { mCurTransaction.commitAllowingStateLoss(); mCurTransaction = null; mFragmentManager.executePendingTransactions(); // Fix: Fragment is added by transaction. BUT didn't add to FragmentManager's mActive. for (Fragment fragment : mFragments) { if (fragment != null) { fixActiveFragment(mFragmentManager, fragment); } } } } @Override public boolean isViewFromObject(View view, Object object) { return ((Fragment) object).getView() == view; } @Override public Parcelable saveState() { Bundle state = null; // 目前顯示的 Fragments for (int i = 0; i < mFragments.size(); i++) { Fragment f = mFragments.get(i); if (f != null && f.isAdded()) { if (state == null) { state = new Bundle(); } String key = "f" + i; mFragmentManager.putFragment(state, key, f); } } if (mFragmentStates.size() > 0) { if (state == null) { state = new Bundle(); } FragmentState[] fs = new FragmentState[mFragmentStates.size()]; mFragmentStates.toArray(fs); state.putParcelableArray("states_fragment", fs); } return state; } @Override public void restoreState(Parcelable state, ClassLoader loader) { if (state != null) { Bundle bundle = (Bundle) state; bundle.setClassLoader(loader); Parcelable[] fs = bundle.getParcelableArray("states_fragment"); mFragments.clear(); mFragmentStates.clear(); mFragmentTags.clear(); mFragmentClassNames.clear(); mFragmentArgs.clear(); if (fs != null) { for (int i = 0; i < fs.length; i++) { FragmentState fragmentState = (FragmentState) fs[i]; mFragmentStates.add(fragmentState); if (fragmentState != null) { mFragmentArgs.add(fragmentState.mArguments); mFragmentTags.add(fragmentState.mTag); mFragmentClassNames.add(fragmentState.mClassName); } else { mFragmentArgs.add(null); mFragmentTags.add(null); mFragmentClassNames.add(null); } mFragments.add(null); } } Iterable<String> keys = bundle.keySet(); for (String key : keys) { if (key.startsWith("f")) { int index = Integer.parseInt(key.substring(1)); Fragment f = mFragmentManager.getFragment(bundle, key); if (f != null) { f.setMenuVisibility(false); mFragments.set(index, f); mFragmentArgs.set(index, f.mArguments); mFragmentTags.set(index, f.mTag); mFragmentClassNames.set(index, f.getClass().getName()); } else { Log.w(TAG, "Bad fragment at key " + key); } } } // If restore will change notifyDataSetChanged(); } } public static void fixActiveFragment(FragmentManager fragmentManager, Fragment fragment) { FragmentManagerImpl fm = (FragmentManagerImpl) fragmentManager; if (fm.mActive != null) { int index = fragment.mIndex; Fragment origin = fm.mActive.get(index); if (origin != null) { if ((origin.mIndex != fragment.mIndex) || !(origin.equals(fragment))) { Log.e(TAG, String.format("fixActiveFragment: Not Equal! Origin: %s %s, Fragment: %s $s", origin.getClass().getName(), origin.mIndex, fragment.getClass().getName(), fragment.mIndex )); } } fm.mActive.set(index, fragment); } } // Fix // http://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android @Override public int getItemPosition(Object object) { int index = mFragments.indexOf(object); if (index < 0) { return PagerAdapter.POSITION_NONE; } boolean isPositionChange = mTempPositionChange[index]; int result = PagerAdapter.POSITION_UNCHANGED; if (isPositionChange) { result = PagerAdapter.POSITION_NONE; } return result; } }
источник
2020 сейчас.
Просто добавьте это в PageAdapter:
override fun getItemPosition(`object`: Any): Int { return PagerAdapter.POSITION_NONE }
источник
Вы можете просто переопределить
destroyItem
метод@Override public void destroyItem(ViewGroup container, int position, Object object) { fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss(); }
источник
Надеюсь, это поможет вам.
private class MyPagerAdapter extends FragmentStatePagerAdapter { //... your existing code @Override public int getItemPosition(Object object){ return PagerAdapter.POSITION_UNCHANGED; } }
источник