Заменить фрагмент внутри ViewPager - PullRequest
256 голосов
/ 11 октября 2011

Я пытаюсь использовать фрагмент с ViewPager, используя FragmentPagerAdapter.Чего я хочу добиться, так это заменить фрагмент, расположенный на первой странице ViewPager, другим.

Пейджер состоит из двух страниц.Первый - FirstPagerFragment, второй - SecondPagerFragment.Нажатие на кнопку первой страницы.Я хотел бы заменить FirstPagerFragment на NextFragment.

Ниже приведен мой код.

public class FragmentPagerActivity extends FragmentActivity {

    static final int NUM_ITEMS = 2;

    MyAdapter mAdapter;
    ViewPager mPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_pager);

        mAdapter = new MyAdapter(getSupportFragmentManager());

        mPager = (ViewPager) findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);

    }


    /**
     * Pager Adapter
     */
    public static class MyAdapter extends FragmentPagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        @Override
        public Fragment getItem(int position) {

            if(position == 0) {
                return FirstPageFragment.newInstance();
            } else {
                return SecondPageFragment.newInstance();
            }

        }
    }


    /**
     * Second Page FRAGMENT
     */
    public static class SecondPageFragment extends Fragment {

        public static SecondPageFragment newInstance() {
            SecondPageFragment f = new SecondPageFragment();
            return f;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            //Log.d("DEBUG", "onCreateView");
            return inflater.inflate(R.layout.second, container, false);

        }
    }

    /**
     * FIRST PAGE FRAGMENT
     */
    public static class FirstPageFragment extends Fragment {

        Button button;

        public static FirstPageFragment newInstance() {
            FirstPageFragment f = new FirstPageFragment();
            return f;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            //Log.d("DEBUG", "onCreateView");
            View root = inflater.inflate(R.layout.first, container, false);
            button = (Button) root.findViewById(R.id.button);
            button.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    FragmentTransaction trans = getFragmentManager().beginTransaction();
                                    trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
                    trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
                    trans.addToBackStack(null);
                    trans.commit();

                }

            });

            return root;
        }

        /**
     * Next Page FRAGMENT in the First Page
     */
    public static class NextFragment extends Fragment {

        public static NextFragment newInstance() {
            NextFragment f = new NextFragment();
            return f;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            //Log.d("DEBUG", "onCreateView");
            return inflater.inflate(R.layout.next, container, false);

        }
    }
}

... и здесь XML-файлы

fragment_pager.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:padding="4dip"
        android:gravity="center_horizontal"
        android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1">
    </android.support.v4.view.ViewPager>

</LinearLayout>

first.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/first_fragment_root_id"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <Button android:id="@+id/button"
     android:layout_width="wrap_content" android:layout_height="wrap_content"
     android:text="to next"/>

</LinearLayout>

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

trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());

?

Если я использую R.id.first_fragment_root_id, замена работает, но Hierarchy Viewer показывает странное поведение, как показано ниже.

В начале ситуация

после замены ситуация будет

Как вы видите, что-то не так, я ожидаю найти то же состояние, что и на первом рисунке после замены фрагмента.

Ответы [ 18 ]

2 голосов
/ 25 июня 2014

Замена фрагментов в окне просмотра довольно сложна, но очень возможна и может выглядеть супер гладко.Во-первых, вам нужно позволить самому viewpager обрабатывать удаление и добавление фрагментов.Что происходит, когда вы заменяете фрагмент внутри SearchFragment, ваш viewpager сохраняет свои представления фрагментов.Таким образом, в итоге вы получаете пустую страницу, потому что SearchFragment удаляется при попытке ее заменить.

Решение состоит в том, чтобы создать прослушиватель внутри вашего окна просмотра, который будет обрабатывать изменения, сделанные вне его, поэтому сначала добавьте этот кодв нижней части вашего адаптера.

public interface nextFragmentListener {
    public void fragment0Changed(String newFragmentIdentification);
}

Затем вам нужно создать закрытый класс в вашем viewpager, который становится слушателем, когда вы хотите изменить свой фрагмент.Например, вы можете добавить что-то вроде этого.Обратите внимание, что он реализует интерфейс, который был только что создан.Поэтому всякий раз, когда вы вызываете этот метод, он запускает код внутри класса ниже.

private final class fragmentChangeListener implements nextFragmentListener {


    @Override
    public void fragment0Changed(String fragment) {
        //I will explain the purpose of fragment0 in a moment
        fragment0 = fragment;
        manager.beginTransaction().remove(fragAt0).commit();

        switch (fragment){
            case "searchFragment":
                fragAt0 = SearchFragment.newInstance(listener);
                break;
            case "searchResultFragment":
                fragAt0 = Fragment_Table.newInstance(listener);
                break;
        }

        notifyDataSetChanged();
    }

Здесь следует указать две основные вещи:

  1. fragAt0 is a "гибкий »фрагмент.Он может принимать любой тип фрагмента, который вы ему дадите.Это позволяет ему стать вашим лучшим другом в замене фрагмента в позиции 0 на нужный вам фрагмент.
  2. Обратите внимание на слушателей, которые размещены в конструкторе 'newInstance (listener).Вот как вы будете вызывать фрагмент 0Changed (String newFragmentIdentification) `.В следующем коде показано, как создать прослушиватель внутри фрагмента.

    static nextFragmentListener listenerSearch;

        public static Fragment_Journals newInstance(nextFragmentListener listener){
                listenerSearch = listener;
                return new Fragment_Journals();
            }
    

Вы можете вызвать изменение внутри вашего onPostExecute

private class SearchAsyncTask extends AsyncTask<Void, Void, Void>{

    protected Void doInBackground(Void... params){
        .
        .//some more operation
        .
    }
    protected void onPostExecute(Void param){

        listenerSearch.fragment0Changed("searchResultFragment");
    }

}

Это приведет к тому, что код внутри вашего viewpager переключит ваш фрагмент в нулевой позиции fragAt0, чтобы стать новым searchResultFragment.Есть еще две маленькие части, которые вам нужно добавить в пейджер, прежде чем он станет функциональным.

Один из них будет в методе переопределения getItem в пейджере.

@Override
public Fragment getItem(int index) {

    switch (index) {
    case 0:
        //this is where it will "remember" which fragment you have just selected. the key is to set a static String fragment at the top of your page that will hold the position that you had just selected.  

        if(fragAt0 == null){

            switch(fragment0){
            case "searchFragment":
                fragAt0 = FragmentSearch.newInstance(listener);
                break;
            case "searchResultsFragment":
                fragAt0 = FragmentSearchResults.newInstance(listener);
                break;
            }
        }
        return fragAt0;
    case 1:
        // Games fragment activity
        return new CreateFragment();

    }

Теперь без этого финалакусок вы все равно получите пустую страницу.Вид хромает, но это неотъемлемая часть viewPager.Вы должны переопределить метод getItemPosition окна просмотра.Обычно этот метод возвращает POSITION_UNCHANGED, который сообщает ViewPager, чтобы все оставалось прежним, и поэтому getItem никогда не будет вызываться для размещения нового фрагмента на странице.Вот пример того, что вы могли бы сделать

public int getItemPosition(Object object)
{
    //object is the current fragment displayed at position 0.  
    if(object instanceof SearchFragment && fragAt0 instanceof SearchResultFragment){
        return POSITION_NONE;
    //this condition is for when you press back
    }else if{(object instanceof SearchResultFragment && fragAt0 instanceof SearchFragment){
        return POSITION_NONE;
    }
        return POSITION_UNCHANGED
}

Как я уже сказал, код сильно усложняется, но вам, в основном, нужно создать собственный адаптер для вашей ситуации.Вещи, которые я упомянул, позволят изменить фрагмент.Скорее всего, потребуется много времени, чтобы все впитать, поэтому я буду терпелив, но все это будет иметь смысл.Совершенно стоит потратить время, потому что это может сделать действительно привлекательное приложение.

Вот самородок для обработки кнопки возврата.Вы помещаете это в MainActivity

 public void onBackPressed() {
    if(mViewPager.getCurrentItem() == 0) {
        if(pagerAdapter.getItem(0) instanceof FragmentSearchResults){
            ((Fragment_Table) pagerAdapter.getItem(0)).backPressed();
        }else if (pagerAdapter.getItem(0) instanceof FragmentSearch) {
            finish();
        }
    }

. Вам нужно будет создать метод с именем backPressed () внутри FragmentSearchResults, который будет вызывать Frag00olated.Это в сочетании с кодом, который я показал ранее, будет обрабатывать нажатие кнопки назад.Удачи вам в вашем коде для изменения виджета.Требуется много работы, и, насколько я обнаружил, нет никаких быстрых адаптаций.Как я уже сказал, вы в основном создаете собственный адаптер viewpager и позволяете ему обрабатывать все необходимые изменения с помощью слушателей

2 голосов
/ 14 октября 2012

Я также сделал решение, которое работает с Stacks .Это более модульный подход, поэтому вам не нужно указывать каждый фрагмент и фрагмент детали в вашем FragmentPagerAdapter.Он построен поверх Примера из ActionbarSherlock, который выводится, если я прав из Google Demo App.

/**
 * This is a helper class that implements the management of tabs and all
 * details of connecting a ViewPager with associated TabHost.  It relies on a
 * trick.  Normally a tab host has a simple API for supplying a View or
 * Intent that each tab will show.  This is not sufficient for switching
 * between pages.  So instead we make the content part of the tab host
 * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
 * view to show as the tab content.  It listens to changes in tabs, and takes
 * care of switch to the correct paged in the ViewPager whenever the selected
 * tab changes.
 * 
 * Changed to support more Layers of fragments on each Tab.
 * by sebnapi (2012)
 * 
 */
public class TabsAdapter extends FragmentPagerAdapter
        implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
    private final Context mContext;
    private final TabHost mTabHost;
    private final ViewPager mViewPager;

    private ArrayList<String> mTabTags = new ArrayList<String>();
    private HashMap<String, Stack<TabInfo>> mTabStackMap = new HashMap<String, Stack<TabInfo>>();

    static final class TabInfo {
        public final String tag;
        public final Class<?> clss;
        public Bundle args;

        TabInfo(String _tag, Class<?> _class, Bundle _args) {
            tag = _tag;
            clss = _class;
            args = _args;
        }
    }

    static class DummyTabFactory implements TabHost.TabContentFactory {
        private final Context mContext;

        public DummyTabFactory(Context context) {
            mContext = context;
        }

        @Override
        public View createTabContent(String tag) {
            View v = new View(mContext);
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }
    }

    public interface SaveStateBundle{
        public Bundle onRemoveFragment(Bundle outState);
    }

    public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
        super(activity.getSupportFragmentManager());
        mContext = activity;
        mTabHost = tabHost;
        mViewPager = pager;
        mTabHost.setOnTabChangedListener(this);
        mViewPager.setAdapter(this);
        mViewPager.setOnPageChangeListener(this);
    }

    /**
     * Add a Tab which will have Fragment Stack. Add Fragments on this Stack by using
     * addFragment(FragmentManager fm, String _tag, Class<?> _class, Bundle _args)
     * The Stack will hold always the default Fragment u add here.
     * 
     * DON'T ADD Tabs with same tag, it's not beeing checked and results in unexpected
     * beahvior.
     * 
     * @param tabSpec
     * @param clss
     * @param args
     */
    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args){
        Stack<TabInfo> tabStack = new Stack<TabInfo>();

        tabSpec.setContent(new DummyTabFactory(mContext));
        mTabHost.addTab(tabSpec);
        String tag = tabSpec.getTag();
        TabInfo info = new TabInfo(tag, clss, args);

        mTabTags.add(tag);                  // to know the position of the tab tag 
        tabStack.add(info);
        mTabStackMap.put(tag, tabStack);
        notifyDataSetChanged();
    }

    /**
     * Will add the Fragment to Tab with the Tag _tag. Provide the Class of the Fragment
     * it will be instantiated by this object. Proivde _args for your Fragment.
     * 
     * @param fm
     * @param _tag
     * @param _class
     * @param _args
     */
    public void addFragment(FragmentManager fm, String _tag, Class<?> _class, Bundle _args){
        TabInfo info = new TabInfo(_tag, _class, _args);
        Stack<TabInfo> tabStack = mTabStackMap.get(_tag);   
        Fragment frag = fm.findFragmentByTag("android:switcher:" + mViewPager.getId() + ":" + mTabTags.indexOf(_tag));
        if(frag instanceof SaveStateBundle){
            Bundle b = new Bundle();
            ((SaveStateBundle) frag).onRemoveFragment(b);
            tabStack.peek().args = b;
        }
        tabStack.add(info);
        FragmentTransaction ft = fm.beginTransaction();
        ft.remove(frag).commit();
        notifyDataSetChanged();
    }

    /**
     * Will pop the Fragment added to the Tab with the Tag _tag
     * 
     * @param fm
     * @param _tag
     * @return
     */
    public boolean popFragment(FragmentManager fm, String _tag){
        Stack<TabInfo> tabStack = mTabStackMap.get(_tag);   
        if(tabStack.size()>1){
            tabStack.pop();
            Fragment frag = fm.findFragmentByTag("android:switcher:" + mViewPager.getId() + ":" + mTabTags.indexOf(_tag));
            FragmentTransaction ft = fm.beginTransaction();
            ft.remove(frag).commit();
            notifyDataSetChanged();
            return true;
        }
        return false;
    }

    public boolean back(FragmentManager fm) {
        int position = mViewPager.getCurrentItem();
        return popFragment(fm, mTabTags.get(position));
    }

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

    @Override
    public int getItemPosition(Object object) {
        ArrayList<Class<?>> positionNoneHack = new ArrayList<Class<?>>();
        for(Stack<TabInfo> tabStack: mTabStackMap.values()){
            positionNoneHack.add(tabStack.peek().clss);
        }   // if the object class lies on top of our stacks, we return default
        if(positionNoneHack.contains(object.getClass())){
            return POSITION_UNCHANGED;
        }
        return POSITION_NONE;
    }

    @Override
    public Fragment getItem(int position) {
        Stack<TabInfo> tabStack = mTabStackMap.get(mTabTags.get(position));
        TabInfo info = tabStack.peek();
        return Fragment.instantiate(mContext, info.clss.getName(), info.args);
    }

    @Override
    public void onTabChanged(String tabId) {
        int position = mTabHost.getCurrentTab();
        mViewPager.setCurrentItem(position);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
        // Unfortunately when TabHost changes the current tab, it kindly
        // also takes care of putting focus on it when not in touch mode.
        // The jerk.
        // This hack tries to prevent this from pulling focus out of our
        // ViewPager.
        TabWidget widget = mTabHost.getTabWidget();
        int oldFocusability = widget.getDescendantFocusability();
        widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
        mTabHost.setCurrentTab(position);
        widget.setDescendantFocusability(oldFocusability);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

}

Добавьте это для кнопки возврата функциональности в MainActivity:

@Override
public void onBackPressed() {
  if (!mTabsAdapter.back(getSupportFragmentManager())) {
    super.onBackPressed();
  }
}

Если вам нравится , сохраните состояние фрагмента , когда оно будет удалено.Позвольте вашему фрагменту реализовать интерфейс SaveStateBundle, возвращающий в функцию пакет с вашим состоянием сохранения.Получите пакет после создания экземпляра с помощью this.getArguments().

Вы можете создать вкладку, подобную этой:

mTabsAdapter.addTab(mTabHost.newTabSpec("firstTabTag").setIndicator("First Tab Title"),
                FirstFragmentActivity.FirstFragmentFragment.class, null);

работает аналогично, если вы хотите добавить фрагмент сверхустека вкладок. Важно : Я думаю, это не сработает, если вы захотите иметь 2 экземпляра одного и того же класса поверх двух вкладок.Я быстро разработал это решение, поэтому могу поделиться им, не предоставляя никакого опыта.

1 голос
/ 08 июня 2015

Я делаю что-то похожее на wize, но в моем ответе вы можете переключаться между двумя фрагментами, когда захотите. И с мудрым ответом у меня есть некоторые проблемы при изменении ориентации экрана и тому подобное. Это выглядит как PagerAdapter:

    public class MyAdapter extends FragmentPagerAdapter
{
    static final int NUM_ITEMS = 2;
    private final FragmentManager mFragmentManager;
    private Fragment mFragmentAtPos0;
     private Map<Integer, String> mFragmentTags;
     private boolean isNextFragment=false;

    public MyAdapter(FragmentManager fm)
    {
        super(fm);
        mFragmentManager = fm;
         mFragmentTags = new HashMap<Integer, String>();
    }

    @Override
    public Fragment getItem(int position)
    {
        if (position == 0)
        {


            if (isPager) {
                mFragmentAtPos0 = new FirstPageFragment();
            } else {
                mFragmentAtPos0 = new NextFragment();
            }
            return mFragmentAtPos0;
        }
        else
            return SecondPageFragment.newInstance();
    }

    @Override
    public int getCount()
    {
        return NUM_ITEMS;
    }


 @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Object obj = super.instantiateItem(container, position);
        if (obj instanceof Fragment) {
            // record the fragment tag here.
            Fragment f = (Fragment) obj;
            String tag = f.getTag();
            mFragmentTags.put(position, tag);
        }
        return obj;
    }


    public void onChange(boolean isNextFragment) {

        if (mFragmentAtPos0 == null)
            mFragmentAtPos0 = getFragment(0);
        if (mFragmentAtPos0 != null)
            mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();


        if (!isNextFragment) {
            mFragmentAtFlashcards = new FirstPageFragment();
        } else {
            mFragmentAtFlashcards = new NextFragment();
        }

        notifyDataSetChanged();


    }


    @Override
    public int getItemPosition(Object object)
    {
        if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment)
            return POSITION_NONE;
         if (object instanceof NextFragment && mFragmentAtPos0 instanceof FirstPageFragment)
            return POSITION_NONE;
        return POSITION_UNCHANGED;
    }


    public Fragment getFragment(int position) {
        String tag = mFragmentTags.get(position);
        if (tag == null)
            return null;
        return mFragmentManager.findFragmentByTag(tag);
    }
}

Слушатель, который я реализовал в контейнере адаптера, чтобы прикрепить его к фрагменту при присоединении, это действие:

    public class PagerContainerActivity extends AppCompatActivity implements ChangeFragmentListener {

//...

  @Override
    public void onChange(boolean isNextFragment) {
        if (pagerAdapter != null)
            pagerAdapter.onChange(isNextFragment);


    }

//...
}

Затем во фрагмент помещается слушатель, когда присоединяется вызывающий:

public class FirstPageFragment extends Fragment{


private ChangeFragmentListener changeFragmentListener;


//...
 @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        changeFragmentListener = ((PagerContainerActivity) activity);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        changeFragmentListener = null;
    }
//...
//in the on click to change the fragment
changeFragmentListener.onChange(true);
//...
}

И, наконец, слушатель:

public interface changeFragmentListener {

    void onChange(boolean isNextFragment);

}
1 голос
/ 12 октября 2012

Вот мое относительно простое решение этой проблемы.Ключи к этому решению - использовать FragmentStatePagerAdapter вместо FragmentPagerAdapter, так как первый удалит неиспользованные фрагменты для вас, в то время как последний все еще сохраняет свои экземпляры.Вторым является использование POSITION_NONE в getItem ().Я использовал простой список, чтобы отслеживать свои фрагменты.Мое требование состояло в том, чтобы заменить весь список фрагментов сразу новым списком, но ниже можно легко изменить отдельные фрагменты:

public class MyFragmentAdapter extends FragmentStatePagerAdapter {
    private List<Fragment> fragmentList = new ArrayList<Fragment>();
    private List<String> tabTitleList = new ArrayList<String>();

    public MyFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    public void addFragments(List<Fragment> fragments, List<String> titles) {
        fragmentList.clear();
        tabTitleList.clear();
        fragmentList.addAll(fragments);
        tabTitleList.addAll(titles);
        notifyDataSetChanged();
    }

    @Override
    public int getItemPosition(Object object) {
        if (fragmentList.contains(object)) {
            return POSITION_UNCHANGED;
        }
        return POSITION_NONE;
    }

    @Override
    public Fragment getItem(int item) {
        if (item >= fragmentList.size()) {
            return null;
        }
        return fragmentList.get(item);
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
        return tabTitleList.get(position);
    }
}
1 голос
/ 22 апреля 2014

Я нашел простое решение, которое отлично работает, даже если вы хотите добавить новые фрагменты посередине или заменить текущий фрагмент. В моем решении вы должны переопределить getItemId(), который должен возвращать уникальный идентификатор для каждого фрагмента. Не позиционируется как по умолчанию.

Есть это:

public class DynamicPagerAdapter extends FragmentPagerAdapter {

private ArrayList<Page> mPages = new ArrayList<Page>();
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();

public DynamicPagerAdapter(FragmentManager fm) {
    super(fm);
}

public void replacePage(int position, Page page) {
    mPages.set(position, page);
    notifyDataSetChanged();
}

public void setPages(ArrayList<Page> pages) {
    mPages = pages;
    notifyDataSetChanged();
}

@Override
public Fragment getItem(int position) {
    if (mPages.get(position).mPageType == PageType.FIRST) {
        return FirstFragment.newInstance(mPages.get(position));
    } else {
        return SecondFragment.newInstance(mPages.get(position));
    }
}

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

@Override
public long getItemId(int position) {
    // return unique id
    return mPages.get(position).getId();
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment fragment = (Fragment) super.instantiateItem(container, position);
    while (mFragments.size() <= position) {
        mFragments.add(null);
    }
    mFragments.set(position, fragment);
    return fragment;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    mFragments.set(position, null);
}

@Override
public int getItemPosition(Object object) {
    PagerFragment pagerFragment = (PagerFragment) object;
    Page page = pagerFragment.getPage();
    int position = mFragments.indexOf(pagerFragment);
    if (page.equals(mPages.get(position))) {
        return POSITION_UNCHANGED;
    } else {
        return POSITION_NONE;
    }
}
}

Примечание: в этом примере FirstFragment и SecondFragment расширяют абстрактный класс PageFragment, который имеет метод getPage().

1 голос
/ 22 июня 2016

Я последовал за ответами @ wize и @ mdelolmo , и я получил решение. Спасибо, Тонны. Но я немного настроил эти решения, чтобы улучшить потребление памяти.

Проблемы, которые я наблюдал:

Они сохраняют экземпляр Fragment, который заменяется. В моем случае это фрагмент, который содержит MapView, и я подумал, что это дорого. Итак, я поддерживаю FragmentPagerPositionChanged (POSITION_NONE or POSITION_UNCHANGED) вместо Fragment.

Вот моя реализация.

  public static class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {

    private SwitchFragListener mSwitchFragListener;
    private Switch mToggle;
    private int pagerAdapterPosChanged = POSITION_UNCHANGED;
    private static final int TOGGLE_ENABLE_POS = 2;


    public DemoCollectionPagerAdapter(FragmentManager fm, Switch toggle) {
        super(fm);
        mToggle = toggle;

        mSwitchFragListener = new SwitchFragListener();
        mToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                mSwitchFragListener.onSwitchToNextFragment();
            }
        });
    }

    @Override
    public Fragment getItem(int i) {
        switch (i)
        {
            case TOGGLE_ENABLE_POS:
                if(mToggle.isChecked())
                {
                    return TabReplaceFragment.getInstance();
                }else
                {
                    return DemoTab2Fragment.getInstance(i);
                }

            default:
                return DemoTabFragment.getInstance(i);
        }
    }

    @Override
    public int getCount() {
        return 5;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "Tab " + (position + 1);
    }

    @Override
    public int getItemPosition(Object object) {

        //  This check make sures getItem() is called only for the required Fragment
        if (object instanceof TabReplaceFragment
                ||  object instanceof DemoTab2Fragment)
            return pagerAdapterPosChanged;

        return POSITION_UNCHANGED;
    }

    /**
     * Switch fragments Interface implementation
     */
    private final class SwitchFragListener implements
            SwitchFragInterface {

        SwitchFragListener() {}

        public void onSwitchToNextFragment() {

            pagerAdapterPosChanged = POSITION_NONE;
            notifyDataSetChanged();
        }
    }

    /**
     * Interface to switch frags
     */
    private interface SwitchFragInterface{
        void onSwitchToNextFragment();
    }
}

Демонстрационная ссылка здесь .. https://youtu.be/l_62uhKkLyM

В демонстрационных целях использовали 2 фрагмента TabReplaceFragment и DemoTab2Fragment в позиции два. Во всех остальных случаях я использую DemoTabFragment экземпляров.

Пояснение:

Я передаю Switch из Activity в DemoCollectionPagerAdapter. На основании состояния этого переключателя мы будем отображать правильный фрагмент. Когда проверка переключателя изменяется, я вызываю метод SwitchFragListener onSwitchToNextFragment, где меняю значение переменной pagerAdapterPosChanged на POSITION_NONE. Узнайте больше о POSITION_NONE . Это сделает недействительным getItem, и у меня есть логика для создания правильного фрагмента там. Извините, если объяснение немного грязное.

Еще раз большое спасибо @wize и @mdelolmo за оригинальную идею.

Надеюсь, это полезно. :)

Дайте мне знать, есть ли в этой реализации какие-либо недостатки. Это будет очень полезно для моего проекта.

0 голосов
/ 28 февраля 2018

Это мой способ достичь этого.

Прежде всего добавьте Root_fragment во вкладку viewPager, в которой вы хотите реализовать событие нажатия кнопки fragment. Пример;

@Override
public Fragment getItem(int position) {
  if(position==0)
      return RootTabFragment.newInstance();
  else
      return SecondPagerFragment.newInstance();
}

Прежде всего, RootTabFragment должен включать FragmentLayout для изменения фрагмента.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/root_frame"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
</FrameLayout>

Затем внутри RootTabFragment onCreateView внедрите fragmentChange для своего FirstPagerFragment

getChildFragmentManager().beginTransaction().replace(R.id.root_frame, FirstPagerFragment.newInstance()).commit();

После этого реализуйте событие onClick для вашей кнопки внутри FirstPagerFragment и снова внесите изменение фрагмента.

getChildFragmentManager().beginTransaction().replace(R.id.root_frame, NextFragment.newInstance()).commit();

Надеюсь, это поможет тебе, парень.

0 голосов
/ 26 ноября 2015

после исследования я нашел решение с коротким кодом.прежде всего создайте публичный экземпляр для фрагмента и просто удалите его в onSaveInstanceState, если фрагмент не воссоздается при изменении ориентации.

...