android viewpager с фрагментами, использующими динамическое добавление FragmentPageAdapter, удаление

У меня есть приложение с tabhost и viewpager. У меня есть одна вкладка, фрагмент исправлен. Мне нужно динамически добавлять вкладку, фрагменты при нажатии переключателя в радиогруппе из первого фрагмента.

Класс MyPagerAdapter:

import java.util.ArrayList;
import java.util.List;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;

public class MyViewPageAdapter extends FragmentPagerAdapter {

    private List<Fragment> fragments = new ArrayList<Fragment>();
    FragmentManager fm;

    public List<Fragment> getFragments() {
        return fragments;
    }

    public void setFragments(List<Fragment> fragments) {
        this.fragments = fragments;
    }

    public MyViewPageAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fm = fm;
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

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

    public void addFragment(Fragment fragment) {
        this.fragments.add(fragment);
        notifyDataSetChanged();
    }

    public void removeFragments() {
        try {
            List<Fragment> newList = new ArrayList<Fragment>();
            Fragment general = fragments.get(0);
            newList.add(general);           
            this.fragments.clear();
            this.fragments = new ArrayList<Fragment>();
            this.fragments = newList;
            notifyDataSetChanged();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void removeItemFromFrament(ViewGroup container, int position, Object object) {
        try {
            try {
                container.removeViewAt(position);
                ((ViewPager) container).setCurrentItem(position - 1);               
            } catch (Exception e) {
                e.printStackTrace();
            }
            notifyDataSetChanged();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Класс MyPagerFragment:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyViewPageFragment extends Fragment {

    private static View mView;

    public static final MyViewPageFragment newInstance(int layoutId) {
        MyViewPageFragment f = new MyViewPageFragment();
        Bundle b = new Bundle();
        b.putInt("layout", layoutId);
        f.setArguments(b);
        return f;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        int layout = getArguments().getInt("layout");
        try {
            mView = inflater.inflate(layout, container, false);
        } catch (Exception e) {
        }
        return mView;
    }

}

Я пытаюсь добавить фрагменты в адаптер следующим образом:

Fragment fragment = MyViewPageFragment.newInstance(R.layout.tab_content_layout);
((MyViewPageAdapter) mViewPager.getAdapter()).addFragment(fragment);

Моя проблема: В первый раз страницы добавляются правильно, после удаления всех представлений (кроме первого фрагмента) и попытки добавить еще один набор вкладок, фрагменты представлений не видны, и getSupportFragmentmanager.getFragments( ).size() неверен.

Я попытался удалить представления из viewpager с помощью диспетчера фрагментов.

FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();

После добавления вкладок фрагменты на страницах прокручиваются, функция getSupportFragmentManager().getFragments.get(arg0) возвращает значение null.

Примечание. Мне нужно сохранить состояние первого фрагмента, поэтому FragmentStatePagerAdapter и getItemPosition возвращают POSITION_NONE недопустимо.


comment
Как вы думаете, this.fragments.clear(); this.fragments = new ArrayList<Fragment>(); this.fragments = newList; прав? Что вы хотите здесь?   -  person SilentKnight    schedule 10.04.2015
comment
Да, я должен поддерживать первый фрагмент, потому что он статичен. Итак, я получаю первый, очищаю все фрагменты и снова добавляю первый фрагмент в список.   -  person User0802    schedule 13.04.2015
comment
вы можете обратиться по ссылке blog.csdn.net/z13759561330/article/details/40737381   -  person tiny sunlight    schedule 29.03.2016


Ответы (2)


Точно так же, как вы специально не вызываете removeView() для ListView из ListAdapter, чтобы избавиться от элемента, вы не удаляете напрямую Fragment с FragmentManager из FragmentPagerAdapter.

Вы должны переопределить getItemPosition(), но вы должны обеспечить немного более разумную реализацию, чем просто возвращать POSITION_NONE все время.

Если ваш первый фрагмент никогда не меняется, всегда возвращайте POSITION_UNCHANGED, когда этот фрагмент передается в getItemPosition()

Думайте об этом как о разговоре между вами и ViewPager/FragmentPagerAdapter. Вот пример:

Вы: «Мне нужно изменить фрагменты вокруг». (звонить notifyDataSetChanged)

Адаптер: «Внимание, я сейчас все изменю». (обратный вызов startUpdate)

Адаптер: «Сколько вкладок вам нужно?» (обратный звонок getCount())

Вы: Три. (возврат '3')

Адаптер: «Хорошо, что ты хочешь, чтобы я сделал с этим первым?» (обратный вызов getItemPosition)

Вы: «Я хочу оставить его там, где он есть». (возврат POSITION_UNCHANGED)

Адаптер: «Отлично, а как насчет второго?» (обратный звонок getItemPosition)

Вы: «Я хочу переместить его на третью вкладку». (возврат '2')

Адаптер: «Хорошо, а третий?» (обратный звонок getItemPosition)

Вы: «Я хочу полностью избавиться от этого». (возврат POSITION_NONE)

Адаптер: «Хорошо, у меня есть место для второй вкладки, какой фрагмент вы хотите, чтобы я использовал?» (обратный звонок getItem)

Вы: «Вот этот». (фрагмент возврата для позиции == 1)

Адаптер: «Я закончил все менять, пока». (обратный звонок finishUpdate)

У меня может быть не совсем правильный порядок вызовов, но основная идея есть.

Если вам нужно сохранить состояние удаленных фрагментов, вы можете переопределить getItem() и destroyItem(), чтобы помочь вам в этом:

private FragmentManager mFragmentManager;

public MyPagerAdapter(FragmentManager fm) {
    super(fm);
    mFragmentManager = fm;
}

@Override
public Fragment getItem(int position) {
    // figure out which fragment you want at this position
    Fragment fragment = new MyFragment();
    // retrieve your savedState from wherever you put it
    fragment.setInitialSavedState(savedState);
    return fragment;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment) object;
    Fragment.SavedState savedState = mFragmentManager.saveFragmentInstanceState(fragment)
    // save your fragment state somewhere here
    super.destroyItem(container, position, object);
}

Ваши фрагменты должны будут реализовать saveState() и restoreState(), чтобы это работало.

person kris larson    schedule 10.04.2015
comment
Спасибо за помощь, Крис. - person User0802; 13.04.2015
comment
Мне нужно поддерживать состояние вновь добавленных фрагментов, пока я не удалю его из списка фрагментов. Поскольку у меня есть текст редактирования во фрагментах, если я верну POSITION_NONE для не первого фрагмента, я не смогу получить предыдущее состояние 2-го и 3-го фрагментов. - person User0802; 13.04.2015
comment
Обновлен мой ответ, чтобы включить некоторый код для сохранения/восстановления состояния фрагмента. - person kris larson; 13.04.2015

Я пробовал то же требование, что и ваше, с FragmentStatePagerAdapter, который работал нормально. Может быть, это могло бы помочь вам.

Чтобы добавить новый фрагмент:

SIZE = SIZE +1;
adapter.instantiateItem(viewPager, SIZE-1);
adapter.notifyDataSetChanged();

В getItem() для «позиции» создайте и верните новый фрагмент (здесь я использовал оператор switch)

Обновите метод getCount(), чтобы он возвращал новый размер.

Дайте мне знать, если вы хотите, чтобы я поделился кодом.

person hrushi    schedule 18.05.2016