ViewPager içindeki Parçayı Değiştirme


268

Fragment ViewPagerkullanarak bir kullanmaya çalışıyorum FragmentPagerAdapter. Ulaşmak için aradığım şey, ilk sayfasında yer alan bir parçayı başka bir parça ile değiştirmek ViewPager.

Çağrı cihazı iki sayfadan oluşur. Birincisi FirstPagerFragment, ikincisi SecondPagerFragment. İlk sayfanın düğmesine tıklamak. FirstPagerFragmentNextFragment ile değiştirmek istiyorum .

Kodum aşağıda.

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

        }
    }
}

... ve burada xml dosyaları

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>

Şimdi sorun ... hangi kimliği kullanmalıyım

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

?

Ben kullanırsanız R.id.first_fragment_root_id, yedek çalışır, ancak Hiyerarşi Görüntüleyici aşağıdaki gibi tuhaf bir davranış gösterir.

Başlangıçta durum

değişimden sonra durum

Gördüğünüz gibi yanlış bir şey var, parçayı değiştirdikten sonra ilk resimde gösterildiği gibi aynı durumu bulmayı umuyorum.


Bu düzen diyagramını bir şekilde mi oluşturdunuz yoksa manuel olarak mı yaptınız?
Jeroen Vannevel

@Noodles: Aynı şeyi yapmam gerek. Sorunuz birçok farklı yanıtı olan uzun bir konu oluşturdu. Sonunda en iyi ne işe yaradı? Çok teşekkürler!
narb

1
@JeroenVannevel daha önce çözmüş olabilirsiniz, ancak bu düzen diyagramı developer.android.com/tools/performance/hierarchy-viewer/…
Ankit Popli

biraz sorun var yardımına ihtiyacım var stackoverflow.com/questions/40149039/…
albert

Yanıtlar:


162

Orada bir modifiye kaynak kodunu gerekmez başka çözüm ViewPagerve FragmentStatePagerAdapterve çalışır FragmentPagerAdapteryazar tarafından kullanılan temel sınıf.

Yazarın hangi kimliği kullanması gerektiği sorusunu cevaplayarak başlamak istiyorum; kabın kimliği, yani görünüm çağrı cihazının kendisinin kimliği. Bununla birlikte, muhtemelen kendinizi fark ettiğiniz gibi, bu kimliği kodunuzda kullanmak hiçbir şeyin olmamasına neden olur. Nedenini açıklayacağım:

Her şeyden önce, ViewPagersayfaları yeniden doldurmak için notifyDataSetChanged(), bağdaştırıcınızın temel sınıfında bulunan aramalısınız .

İkincisi, hangi sayfaların yok edilmesi ve hangilerinin saklanması gerektiğini kontrol etmek ViewPageriçin getItemPosition()soyut yöntemi kullanır . Bu işlevin varsayılan uygulaması her zaman geri döner POSITION_UNCHANGED, bu da ViewPagertüm geçerli sayfaların korunmasına neden olur ve sonuç olarak yeni sayfanızı eklemez. Bu nedenle, parça değiştirme işini yapmak getItemPosition()için adaptörünüzde geçersiz kılınmalı ve POSITION_NONEeski, gizli olmak için bir argüman olarak çağrıldığında geri dönmelidir .

Bu aynı zamanda adaptör daima 0 pozisyonunda, görüntülenmesi gereken hangi parçanın farkında olması gerektiği anlamına gelir FirstPageFragmentveya NextFragment. Bunu yapmanın bir yolu, FirstPageFragmentparçaları değiştirmenin zamanı geldiğinde çağrılacak bir dinleyici sağlamaktır . Ben, senin parçası adaptör kolu izin tüm fragman geçer ve çağrılar olsa bu iyi bir şey olduğunu düşünüyorum ViewPagerve FragmentManager.

Üçüncüsü, FragmentPagerAdapterkullanılan parçaları konumdan türetilen bir adla önbelleğe alır, bu nedenle 0 konumunda bir parça varsa, sınıf yeni olmasına rağmen değiştirilmez. İki çözüm var, ancak en basit olanı, etiketini de kaldıracak remove()işlevini kullanmaktır FragmentTransaction.

Çok fazla metin vardı, işte sizin durumunuzda çalışması gereken kod:

public class MyAdapter extends FragmentPagerAdapter
{
    static final int NUM_ITEMS = 2;
    private final FragmentManager mFragmentManager;
    private Fragment mFragmentAtPos0;

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

    @Override
    public Fragment getItem(int position)
    {
        if (position == 0)
        {
            if (mFragmentAtPos0 == null)
            {
                mFragmentAtPos0 = FirstPageFragment.newInstance(new FirstPageFragmentListener()
                {
                    public void onSwitchToNextFragment()
                    {
                        mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();
                        mFragmentAtPos0 = NextFragment.newInstance();
                        notifyDataSetChanged();
                    }
                });
            }
            return mFragmentAtPos0;
        }
        else
            return SecondPageFragment.newInstance();
    }

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

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

public interface FirstPageFragmentListener
{
    void onSwitchToNextFragment();
}

Umarım bu herkese yardımcı olur!


24
benim için de çalışır, ancak ilk parçayı göstermek için geri düğmesini nasıl uygulayabilirim?
user1159819

6
Harika bir açıklama ama bunun tam kaynak kodunu, özellikle FirstPageFragment ve SecondPageFragment sınıflarını yayınlayabilirsiniz.
georgiecasey

6
FirstPageFragmentListener öğesini newInstance () içindeki Bundle'a nasıl eklersiniz?
miguel

4
FirstPageFragment.newInstance()Dinleyici parametresi ile işlem yaptığınız kodu ekleyebilir misiniz ?
MiguelHincapieC

6
Bu, yalnızca parçayı kaldırırken commit () yerine commitNow () çağırdığımda benim için çalışır. Kullanım durumumun neden farklı olduğundan emin değilim, ancak umarım bu biraz zaman kazandıracaktır.
Ian Lovejoy

37

13 Kasım 2012 itibariyle, bir ViewPager'daki parçaları yeniden düzenlemek çok daha kolay hale geldi. Google, iç içe geçmiş parçaları destekleyerek Android 4.2'yi yayınladı ve yeni Android Destek Kütüphanesi v11'de de desteklendi, bu da 1.6'ya kadar çalışacak

GetChildFragmentManager'ı kullanmanız dışında bir parçayı değiştirmenin normal yoluna çok benzer. Kullanıcı geri düğmesini tıklattığında, iç içe geçmiş parça backstack patlamaması dışında çalışıyor gibi görünüyor . Bu bağlantılı sorudaki çözüme göre, parçanın alt yöneticisindeki popBackStackImmediate () öğesini el ile çağırmanız gerekir. Bu nedenle, ViewPager'in geçerli parçasını alacağınız ve getChildFragmentManager (). PopBackStackImmediate () öğesini çağıracağınız ViewPager etkinliğinin onBackPressed () yöntemini geçersiz kılmanız gerekir.

Şu anda görüntülenen Parçayı almak da biraz kötü, bu kirli "android: switcher: VIEWPAGER_ID: INDEX" çözümünü kullandım, ancak aynı zamanda bu sayfadaki ikinci çözümde açıklandığı gibi ViewPager'in tüm parçalarını kendiniz de takip edebilirsiniz .

İşte kullanıcı bir satırı tıkladığında ve geri düğmesi çalışırken ViewPager'de ayrıntılı bir görünüme sahip 4 ListViews içeren bir ViewPager kodum. Ben kısaca uğruna sadece ilgili kodu dahil etmeye çalıştım, bu yüzden tam uygulamanın GitHub'a yüklenmesini istiyorsanız bir yorum bırakın.

HomeActivity.java

 public class HomeActivity extends SherlockFragmentActivity {
FragmentAdapter mAdapter;
ViewPager mPager;
TabPageIndicator mIndicator;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mAdapter = new FragmentAdapter(getSupportFragmentManager());
    mPager = (ViewPager)findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
    mIndicator.setViewPager(mPager);
}

// This the important bit to make sure the back button works when you're nesting fragments. Very hacky, all it takes is some Google engineer to change that ViewPager view tag to break this in a future Android update.
@Override
public void onBackPressed() {
    Fragment fragment = (Fragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":"+mPager.getCurrentItem());
    if (fragment != null) // could be null if not instantiated yet
    {
        if (fragment.getView() != null) {
            // Pop the backstack on the ChildManager if there is any. If not, close this activity as normal.
            if (!fragment.getChildFragmentManager().popBackStackImmediate()) {
                finish();
            }
        }
    }
}

class FragmentAdapter extends FragmentPagerAdapter {        
    public FragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
        case 0:
            return ListProductsFragment.newInstance();
        case 1:
            return ListActiveSubstancesFragment.newInstance();
        case 2:
            return ListProductFunctionsFragment.newInstance();
        case 3:
            return ListCropsFragment.newInstance();
        default:
            return null;
        }
    }

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

 }
}

ListProductsFragment.java

public class ListProductsFragment extends SherlockFragment {
private ListView list;

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View V = inflater.inflate(R.layout.list, container, false);
    list = (ListView)V.findViewById(android.R.id.list);
    list.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) {
          // This is important bit
          Fragment productDetailFragment = FragmentProductDetail.newInstance();
          FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
          transaction.addToBackStack(null);
          transaction.replace(R.id.products_list_linear, productDetailFragment).commit();
        }
      });       
    return V;
}
}

7
Kodunuzu github'a yüklemeniz mümkün olacak mı? Teşekkürler.
Gautham

4
@georgiecasey: getChildFragmentManager () kullanmaya başlamama izin veren API 17, Android 4.2'yi indirdim. Ama şimdi ekranda eski + yeni parçaları üst üste bindiğim için çözümünüzden bir şey eksik olmalıyım. Not: Çözümünüzü developer.android.com/reference/android/support/v4/view/… adresindeki Google örnek TabsAdapter koduyla birlikte kullanmaya çalışıyorum . Her türlü öneri ve / veya referans kodu için teşekkürler.
gcl1

27
R.id.products_list_linear ne anlama geliyor? Lütfen teklif ettiğiniz gibi kodunuza bağlantı verin.
howettl

1
@ dış parça elemanına kimlik referanslarını nasıl gösterir? Bu sorunu çözmenin anahtarı iç içe geçmiş parçaları kullanmaktır (bu şekilde viewpager bağdaştırıcısını değiştirmek zorunda kalmazsınız).
Indrek Kõue

2
Bu hiç github için yaptın mı?
Baruch

32

Yararlı ve zarif bulduğum @wize'ın cevabına dayanarak, kısmen istediğimi başarabilirim, çünkü değiştirildikten sonra ilk Fragment'e geri dönme yeteneğini istedim. Biraz kodunu biraz değiştirerek başardım.

Bu FragmentPagerAdapter olurdu:

public static class MyAdapter extends FragmentPagerAdapter {
    private final class CalendarPageListener implements
            CalendarPageFragmentListener {
        public void onSwitchToNextFragment() {
            mFragmentManager.beginTransaction().remove(mFragmentAtPos0)
                    .commit();
            if (mFragmentAtPos0 instanceof FirstFragment){
                mFragmentAtPos0 = NextFragment.newInstance(listener);
            }else{ // Instance of NextFragment
                mFragmentAtPos0 = FirstFragment.newInstance(listener);
            }
            notifyDataSetChanged();
        }
    }

    CalendarPageListener listener = new CalendarPageListener();;
    private Fragment mFragmentAtPos0;
    private FragmentManager mFragmentManager;

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

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

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

    @Override
    public Fragment getItem(int position) {
        if (position == 0)
            return Portada.newInstance();
        if (position == 1) { // Position where you want to replace fragments
            if (mFragmentAtPos0 == null) {
                mFragmentAtPos0 = FirstFragment.newInstance(listener);
            }
            return mFragmentAtPos0;
        }
        if (position == 2)
            return Clasificacion.newInstance();
        if (position == 3)
            return Informacion.newInstance();

        return null;
    }
}

public interface CalendarPageFragmentListener {
    void onSwitchToNextFragment();
}

Değiştirmeyi sağlamak için, türden statik bir alan tanımlayın ve karşılık gelen fragmanların yöntemleri CalendarPageFragmentListenerile başlatılır newInstanceve çağırır FirstFragment.pageListener.onSwitchToNextFragment()veya NextFragment.pageListener.onSwitchToNextFragment()sırayla.


Değişim işlemini nasıl yapıyorsunuz? onSwitchToNext yöntemini geçersiz kılmadan Dinleyiciyi başlatmak mümkün değildir.
Leandros

1
Cihazı döndürürseniz mFragmentAtPos0'a kaydedilen durumu kaybetmez misiniz?
seb

@seb, aslında mFragmentAtPos0aktivite durumunu kaydederken referans kaydetmek için bu çözümü geliştirdim . En zarif çözüm değil, işe yarıyor.
mdelolmo

Cevabımı görebilirsiniz . Parçaların yerini alır ve birincisine geri döner.
Lyd

@mdelolmo ViewPager hakkında bu soruya göz atabilir misiniz? Teşekkür ederim stackoverflow.com/questions/27937250/…
Hoa Vu

21

Şunun için bir çözüm uyguladım:

  • Sekme içinde dinamik parça değişimi
  • Sekme başına geçmişin bakımı
  • Yön değişiklikleriyle çalışma

Bunu başarmak için püf noktaları şunlardır:

  • Parça değişimini uygulamak için notifyDataSetChanged () yöntemini kullanın
  • Parça yöneticisini sadece arka aşama için kullanın ve parça değiştirme için hayır
  • Hatıra desenini (yığını) kullanarak geçmişi koruyun

Bağdaştırıcı kodu şudur:

public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

/** The sherlock fragment activity. */
private final SherlockFragmentActivity mActivity;

/** The action bar. */
private final ActionBar mActionBar;

/** The pager. */
private final ViewPager mPager;

/** The tabs. */
private List<TabInfo> mTabs = new LinkedList<TabInfo>();

/** The total number of tabs. */
private int TOTAL_TABS;

private Map<Integer, Stack<TabInfo>> history = new HashMap<Integer, Stack<TabInfo>>();

/**
 * Creates a new instance.
 *
 * @param activity the activity
 * @param pager    the pager
 */
public TabsAdapter(SherlockFragmentActivity activity, ViewPager pager) {
    super(activity.getSupportFragmentManager());
    activity.getSupportFragmentManager();
    this.mActivity = activity;
    this.mActionBar = activity.getSupportActionBar();
    this.mPager = pager;
    mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}

/**
 * Adds the tab.
 *
 * @param image         the image
 * @param fragmentClass the class
 * @param args          the arguments
 */
public void addTab(final Drawable image, final Class fragmentClass, final Bundle args) {
    final TabInfo tabInfo = new TabInfo(fragmentClass, args);
    final ActionBar.Tab tab = mActionBar.newTab();
    tab.setTabListener(this);
    tab.setTag(tabInfo);
    tab.setIcon(image);

    mTabs.add(tabInfo);
    mActionBar.addTab(tab);

    notifyDataSetChanged();
}

@Override
public Fragment getItem(final int position) {
    final TabInfo tabInfo = mTabs.get(position);
    return Fragment.instantiate(mActivity, tabInfo.fragmentClass.getName(), tabInfo.args);
}

@Override
public int getItemPosition(final Object object) {
    /* Get the current position. */
    int position = mActionBar.getSelectedTab().getPosition();

    /* The default value. */
    int pos = POSITION_NONE;
    if (history.get(position).isEmpty()) {
        return POSITION_NONE;
    }

    /* Checks if the object exists in current history. */
    for (Stack<TabInfo> stack : history.values()) {
        TabInfo c = stack.peek();
        if (c.fragmentClass.getName().equals(object.getClass().getName())) {
            pos = POSITION_UNCHANGED;
            break;
        }
    }
    return pos;
}

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

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

@Override
public void onTabSelected(final ActionBar.Tab tab, final FragmentTransaction ft) {
    TabInfo tabInfo = (TabInfo) tab.getTag();
    for (int i = 0; i < mTabs.size(); i++) {
        if (mTabs.get(i).equals(tabInfo)) {
            mPager.setCurrentItem(i);
        }
    }
}

@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}

@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}

public void replace(final int position, final Class fragmentClass, final Bundle args) {
    /* Save the fragment to the history. */
    mActivity.getSupportFragmentManager().beginTransaction().addToBackStack(null).commit();

    /* Update the tabs. */
    updateTabs(new TabInfo(fragmentClass, args), position);

    /* Updates the history. */
    history.get(position).push(new TabInfo(mTabs.get(position).fragmentClass, mTabs.get(position).args));

    notifyDataSetChanged();
}

/**
 * Updates the tabs.
 *
 * @param tabInfo
 *          the new tab info
 * @param position
 *          the position
 */
private void updateTabs(final TabInfo tabInfo, final int position) {
    mTabs.remove(position);
    mTabs.add(position, tabInfo);
    mActionBar.getTabAt(position).setTag(tabInfo);
}

/**
 * Creates the history using the current state.
 */
public void createHistory() {
    int position = 0;
    TOTAL_TABS = mTabs.size();
    for (TabInfo mTab : mTabs) {
        if (history.get(position) == null) {
            history.put(position, new Stack<TabInfo>());
        }
        history.get(position).push(new TabInfo(mTab.fragmentClass, mTab.args));
        position++;
    }
}

/**
 * Called on back
 */
public void back() {
    int position = mActionBar.getSelectedTab().getPosition();
    if (!historyIsEmpty(position)) {
        /* In case there is not any other item in the history, then finalize the activity. */
        if (isLastItemInHistory(position)) {
            mActivity.finish();
        }
        final TabInfo currentTabInfo = getPrevious(position);
        mTabs.clear();
        for (int i = 0; i < TOTAL_TABS; i++) {
            if (i == position) {
                mTabs.add(new TabInfo(currentTabInfo.fragmentClass, currentTabInfo.args));
            } else {
                TabInfo otherTabInfo = history.get(i).peek();
                mTabs.add(new TabInfo(otherTabInfo.fragmentClass, otherTabInfo.args));
            }
        }
    }
    mActionBar.selectTab(mActionBar.getTabAt(position));
    notifyDataSetChanged();
}

/**
 * Returns if the history is empty.
 *
 * @param position
 *          the position
 * @return  the flag if empty
 */
private boolean historyIsEmpty(final int position) {
    return history == null || history.isEmpty() || history.get(position).isEmpty();
}

private boolean isLastItemInHistory(final int position) {
    return history.get(position).size() == 1;
}

/**
 * Returns the previous state by the position provided.
 *
 * @param position
 *          the position
 * @return  the tab info
 */
private TabInfo getPrevious(final int position) {
    TabInfo currentTabInfo = history.get(position).pop();
    if (!history.get(position).isEmpty()) {
        currentTabInfo = history.get(position).peek();
    }
    return currentTabInfo;
}

/** The tab info class */
private static class TabInfo {

    /** The fragment class. */
    public Class fragmentClass;

    /** The args.*/
    public Bundle args;

    /**
     * Creates a new instance.
     *
     * @param fragmentClass
     *          the fragment class
     * @param args
     *          the args
     */
    public TabInfo(Class fragmentClass, Bundle args) {
        this.fragmentClass = fragmentClass;
        this.args = args;
    }

    @Override
    public boolean equals(final Object o) {
        return this.fragmentClass.getName().equals(o.getClass().getName());
    }

    @Override
    public int hashCode() {
        return fragmentClass.getName() != null ? fragmentClass.getName().hashCode() : 0;
    }

    @Override
    public String toString() {
        return "TabInfo{" +
                "fragmentClass=" + fragmentClass +
                '}';
    }
}

Tüm sekmeleri ilk kez eklediğinizde, ilk geçmişi oluşturmak için createHistory () yöntemini çağırmamız gerekir.

public void createHistory() {
    int position = 0;
    TOTAL_TABS = mTabs.size();
    for (TabInfo mTab : mTabs) {
        if (history.get(position) == null) {
            history.put(position, new Stack<TabInfo>());
        }
        history.get(position).push(new TabInfo(mTab.fragmentClass, mTab.args));
        position++;
    }
}

Bir parçayı belirli bir sekmeye her değiştirmek istediğinizde: replace (son int konumu, son Sınıf fragmentClass, son Paket bağımsız değişkenleri)

/* Save the fragment to the history. */
    mActivity.getSupportFragmentManager().beginTransaction().addToBackStack(null).commit();

    /* Update the tabs. */
    updateTabs(new TabInfo(fragmentClass, args), position);

    /* Updates the history. */
    history.get(position).push(new TabInfo(mTabs.get(position).fragmentClass, mTabs.get(position).args));

    notifyDataSetChanged();

Geri basıldığında back () yöntemini çağırmanız gerekir:

public void back() {
    int position = mActionBar.getSelectedTab().getPosition();
    if (!historyIsEmpty(position)) {
        /* In case there is not any other item in the history, then finalize the activity. */
        if (isLastItemInHistory(position)) {
            mActivity.finish();
        }
        final TabInfo currentTabInfo = getPrevious(position);
        mTabs.clear();
        for (int i = 0; i < TOTAL_TABS; i++) {
            if (i == position) {
                mTabs.add(new TabInfo(currentTabInfo.fragmentClass, currentTabInfo.args));
            } else {
                TabInfo otherTabInfo = history.get(i).peek();
                mTabs.add(new TabInfo(otherTabInfo.fragmentClass, otherTabInfo.args));
            }
        }
    }
    mActionBar.selectTab(mActionBar.getTabAt(position));
    notifyDataSetChanged();
}

Çözüm, sherlock eylem çubuğu ve kaydırma hareketi ile çalışır.


bu harika! Github üzerine koyabilir misin?
Nicramus

Bu uygulama, burada sağlananların en temizidir ve her sorunu ele alır. Kabul edilen cevap olmalı.
dazedviper

Herkes bu uygulama ile ilgili sorunlar var mıydı? 2 tanesine sahibim. 1. ilk geri kayıt değil - kayıt için iki kez tıklamak zorunda. 2. a sekmesinde geri (iki kez) tıkladıktan ve b sekmesine gidip a sekmesine geri döndüğümde, b sekmesinin içeriğini gösterir
yaronbic 19:15

7

tl; dr: Barındırılan içeriğinin değiştirilmesinden sorumlu olan ve bir geri gezinme geçmişini (tarayıcıdaki gibi) izleyen bir ana bilgisayar parçası kullanın.

Kullanım durumunuz sabit sayıda sekmeden oluştuğundan, çözümüm iyi çalışır: Fikir, ViewPager'i HostFragmentbarındırılan içeriği değiştirebilen ve kendi geri gezinme geçmişini koruyan özel bir sınıfın örnekleriyle doldurmaktır . Barındırılan parçayı değiştirmek için yönteme bir çağrı yaparsınız hostfragment.replaceFragment():

public void replaceFragment(Fragment fragment, boolean addToBackstack) {
    if (addToBackstack) {
        getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit();
    } else {
        getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit();
    }
}

Tüm bu yöntem, çerçeve düzenini R.id.hosted_fragment, yönteme sağlanan parça ile id ile değiştirmektir .

Daha fazla ayrıntı ve GitHub'da tam bir çalışma örneği için bu konudaki eğitimime bakın!


Bu daha hantal görünse de, bunu yapmanın en iyi yolu (yapı ve bakım kolaylığı açısından) bence.
Sira Lam

Sonunda bir NPE kafa karıştırıyorum. : / Değiştirilecek Görünüm bulunamıyor
Fariz Fakkel

6

Sunulan çözümlerden bazıları sorunu kısmen çözmeme çok yardımcı oldu, ancak bazı durumlarda parça içeriği yerine beklenmedik istisnalar ve siyah sayfa içeriği üreten çözümlerde eksik olan önemli bir şey var.

Mesele şu ki, FragmentPagerAdapter sınıfı, önbelleğe alınmış parçaları FragmentManager'a depolamak için öğe kimliğini kullanıyor . Bu nedenle, ayrıca geçersiz kılmak gerekir getItemId (int konum) o örneğin verir, böylece yöntemi konumunu üst düzey sayfaları ve için 100 + pozisyon ayrıntıları sayfaları için. Aksi takdirde, önceden oluşturulan üst düzey parça, ayrıntı seviyesi parça yerine önbellekten döndürülür.

Dahası, ben burada nasıl faaliyeti sekmeleri benzeri uygulamak için eksiksiz bir örnek paylaşıyorum Fragment kullanan sayfalarda ViewPager ve kullanan sekme düğmeleri RadioGroup ayrıntılı sayfaları ile üst düzey sayfalara değiştirilmesini sağlar ve aynı zamanda geri düğmesine destekler. Bu uygulama, yalnızca bir düzey arka istiflemeyi (öğe listesi - öğe ayrıntıları) destekler, ancak çok düzeyli arka istifleme uygulaması basittir. Bu örnek , örneğin ikinci sayfaya geçtiğinizde, ilk sayfanın parçasını değiştirdiğinizde (görünür değilken) ve ilk sayfaya geri döndüğünüzde bir NullPointerException oluşturması dışında normal durumlarda oldukça iyi çalışır . Bunu çözdüğümde bu soruna bir çözüm göndereceğim:

public class TabsActivity extends FragmentActivity {

  public static final int PAGE_COUNT = 3;
  public static final int FIRST_PAGE = 0;
  public static final int SECOND_PAGE = 1;
  public static final int THIRD_PAGE = 2;

  /**
   * Opens a new inferior page at specified tab position and adds the current page into back
   * stack.
   */
  public void startPage(int position, Fragment content) {
    // Replace page adapter fragment at position.
    mPagerAdapter.start(position, content);
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Initialize basic layout.
    this.setContentView(R.layout.tabs_activity);

    // Add tab fragments to view pager.
    {
      // Create fragments adapter.
      mPagerAdapter = new PagerAdapter(pager);
      ViewPager pager = (ViewPager) super.findViewById(R.id.tabs_view_pager);
      pager.setAdapter(mPagerAdapter);

      // Update active tab in tab bar when page changes.
      pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int index, float value, int nextIndex) {
          // Not used.
        }

        @Override
        public void onPageSelected(int index) {
          RadioGroup tabs_radio_group = (RadioGroup) TabsActivity.this.findViewById(
            R.id.tabs_radio_group);
          switch (index) {
            case 0: {
              tabs_radio_group.check(R.id.first_radio_button);
            }
            break;
            case 1: {
              tabs_radio_group.check(R.id.second_radio_button);
            }
            break;
            case 2: {
              tabs_radio_group.check(R.id.third_radio_button);
            }
            break;
          }
        }

        @Override
        public void onPageScrollStateChanged(int index) {
          // Not used.
        }
      });
    }

    // Set "tabs" radio group on checked change listener that changes the displayed page.
    RadioGroup radio_group = (RadioGroup) this.findViewById(R.id.tabs_radio_group);
    radio_group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
      @Override
      public void onCheckedChanged(RadioGroup radioGroup, int id) {
        // Get view pager representing tabs.
        ViewPager view_pager = (ViewPager) TabsActivity.this.findViewById(R.id.tabs_view_pager);
        if (view_pager == null) {
          return;
        }

        // Change the active page.
        switch (id) {
          case R.id.first_radio_button: {
            view_pager.setCurrentItem(FIRST_PAGE);
          }
          break;
          case R.id.second_radio_button: {
            view_pager.setCurrentItem(SECOND_PAGE);
          }
          break;
          case R.id.third_radio_button: {
            view_pager.setCurrentItem(THIRD_PAGE);
          }
          break;
        }
      });
    }
  }

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

  /**
   * Serves the fragments when paging.
   */
  private class PagerAdapter extends FragmentPagerAdapter {

    public PagerAdapter(ViewPager container) {
      super(TabsActivity.this.getSupportFragmentManager());

      mContainer = container;
      mFragmentManager = TabsActivity.this.getSupportFragmentManager();

      // Prepare "empty" list of fragments.
      mFragments = new ArrayList<Fragment>(){};
      mBackFragments = new ArrayList<Fragment>(){};
      for (int i = 0; i < PAGE_COUNT; i++) {
        mFragments.add(null);
        mBackFragments.add(null);
      }
    }

    /**
     * Replaces the view pager fragment at specified position.
     */
    public void replace(int position, Fragment fragment) {
      // Get currently active fragment.
      Fragment old_fragment = mFragments.get(position);
      if (old_fragment == null) {
        return;
      }

      // Replace the fragment using transaction and in underlaying array list.
      // NOTE .addToBackStack(null) doesn't work
      this.startUpdate(mContainer);
      mFragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
        .remove(old_fragment).add(mContainer.getId(), fragment)
        .commit();
      mFragments.set(position, fragment);
      this.notifyDataSetChanged();
      this.finishUpdate(mContainer);
    }

    /**
     * Replaces the fragment at specified position and stores the current fragment to back stack
     * so it can be restored by #back().
     */
    public void start(int position, Fragment fragment) {
      // Remember current fragment.
      mBackFragments.set(position, mFragments.get(position));

      // Replace the displayed fragment.
      this.replace(position, fragment);
    }

    /**
     * Replaces the current fragment by fragment stored in back stack. Does nothing and returns
     * false if no fragment is back-stacked.
     */
    public boolean back() {
      int position = mContainer.getCurrentItem();
      Fragment fragment = mBackFragments.get(position);
      if (fragment == null) {
        // Nothing to go back.
        return false;
      }

      // Restore the remembered fragment and remove it from back fragments.
      this.replace(position, fragment);
      mBackFragments.set(position, null);
      return true;
    }

    /**
     * Returns fragment of a page at specified position.
     */
    @Override
    public Fragment getItem(int position) {
      // If fragment not yet initialized, create its instance.
      if (mFragments.get(position) == null) {
        switch (position) {
          case FIRST_PAGE: {
            mFragments.set(FIRST_PAGE, new DefaultFirstFragment());
          }
          break;
          case SECOND_PAGE: {
            mFragments.set(SECOND_PAGE, new DefaultSecondFragment());
          }
          break;
          case THIRD_PAGE: {
            mFragments.set(THIRD_PAGE, new DefaultThirdFragment());
          }
          break;
        }
      }

      // Return fragment instance at requested position.
      return mFragments.get(position);
    }

    /**
     * Custom item ID resolution. Needed for proper page fragment caching.
     * @see FragmentPagerAdapter#getItemId(int).
     */
    @Override
    public long getItemId(int position) {
      // Fragments from second level page hierarchy have their ID raised above 100. This is
      // important to FragmentPagerAdapter because it is caching fragments to FragmentManager with
      // this item ID key.
      Fragment item = mFragments.get(position);
      if (item != null) {
        if ((item instanceof NewFirstFragment) || (item instanceof NewSecondFragment) ||
          (item instanceof NewThirdFragment)) {
          return 100 + position;
        }
      }

      return position;
    }

    /**
     * Returns number of pages.
     */
    @Override
    public int getCount() {
      return mFragments.size();
    }

    @Override
    public int getItemPosition(Object object)
    {
      int position = POSITION_UNCHANGED;
      if ((object instanceof DefaultFirstFragment) || (object instanceof NewFirstFragment)) {
        if (object.getClass() != mFragments.get(FIRST_PAGE).getClass()) {
          position = POSITION_NONE;
        }
      }
      if ((object instanceof DefaultSecondragment) || (object instanceof NewSecondFragment)) {
        if (object.getClass() != mFragments.get(SECOND_PAGE).getClass()) {
          position = POSITION_NONE;
        }
      }
      if ((object instanceof DefaultThirdFragment) || (object instanceof NewThirdFragment)) {
        if (object.getClass() != mFragments.get(THIRD_PAGE).getClass()) {
          position = POSITION_NONE;
        }
      }
      return position;
    }

    private ViewPager mContainer;
    private FragmentManager mFragmentManager;

    /**
     * List of page fragments.
     */
    private List<Fragment> mFragments;

    /**
     * List of page fragments to return to in onBack();
     */
    private List<Fragment> mBackFragments;
  }

  /**
   * Tab fragments adapter.
   */
  private PagerAdapter mPagerAdapter;
}

Hmm, bu kodla ilgili başka bir sorun daha var. Kaldırılan ve yeniden eklenen parçadan bir etkinlik başlatmak istediğinizde bir hata iletisi alıyorum: "Hata kaydetme durumu: active NewFirstFragment {405478a0} dizin temizledi: -1" (tam yığın izleme: nopaste.info/547a23dfea.html ). Android kaynaklarına baktığımda, backstack ile ilgili bir şey olduğunu anladım, ancak şu ana kadar nasıl düzeltileceğini bilmiyorum. Kimsenin bir ipucu var mı?
Blackhex

2
Serin, <pre> mFragmentManager.beginTransaction (). Detach (old_fragment) .attach (fragment) .commit (); </code> yerine <pre> mFragmentManager.beginTransaction (). SetTransition (FragmentTransaction.TRANSIT_FRAGment_OPEN). old_fragment) .add (mContainer.getId (), fragment) .commit (); </pre> yukarıdaki örnekte her iki sorunu da gidermiş gibi görünüyor :-).
Blackhex

1
Bu yöntemi kullanırsanız, cihazı döndürürken Android'in Etkinliğinizi yeniden oluşturmasına izin vermediğinizden emin olun. Aksi takdirde, PagerAdapter yeniden oluşturulur ve mBackFragments öğelerinizi kaybedersiniz. Bu aynı zamanda FragmentManager'ı ciddi şekilde karıştırır. BackStack kullanımı, PagerAdapter daha karmaşık bir uygulama pahasına (yani FragmentPagerAdapter'den devralamazsınız.)
Norman

6

Dizin 2 ve 3 için 3 eleman ve 2 alt eleman ile bir ViewPager oluşturduk ve burada ne yapmak istedim ..

resim açıklamasını buraya girin

Bu StackOverFlow önceki soru ve cevapların yardımıyla uyguladık ve işte bağlantı.

ViewPagerChildFragments


Cihazı döndürürseniz projeniz başarısız olur.
Dory

6

Bir içinde bir parçasını değiştirmek için ViewPagerkaynak kodlarını taşıyabilirsiniz size ViewPager, PagerAdapterve FragmentStatePagerAdapterprojenize sınıfları ve kod aşağıdaki ekleyin.

içine ViewPager:

public void notifyItemChanged(Object oldItem, Object newItem) {
    if (mItems != null) {
            for (ItemInfo itemInfo : mItems) {
                        if (itemInfo.object.equals(oldItem)) {
                                itemInfo.object = newItem;
                        }
                    }
       }
       invalidate();
    }

içine FragmentStatePagerAdapter:

public void replaceFragmetns(ViewPager container, Fragment oldFragment, Fragment newFragment) {
       startUpdate(container);

       // remove old fragment

       if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
       int position = getFragmentPosition(oldFragment);
        while (mSavedState.size() <= position) {
            mSavedState.add(null);
        }
        mSavedState.set(position, null);
        mFragments.set(position, null);

        mCurTransaction.remove(oldFragment);

        // add new fragment

        while (mFragments.size() <= position) {
            mFragments.add(null);
        }
        mFragments.set(position, newFragment);
        mCurTransaction.add(container.getId(), newFragment);

       finishUpdate(container);

       // ensure getItem returns newFragemtn after calling handleGetItemInbalidated()
       handleGetItemInbalidated(container, oldFragment, newFragment);

       container.notifyItemChanged(oldFragment, newFragment);
    }

protected abstract void handleGetItemInbalidated(View container, Fragment oldFragment, Fragment newFragment);
protected abstract int  getFragmentPosition(Fragment fragment);

handleGetItemInvalidated()bir sonraki çağrıdan sonra getItem()newFragment öğesinin getFragmentPosition()adaptörünüzdeki parçanın konumunu döndürmesini sağlar .

Şimdi, parçaları değiştirmek için arayın

mAdapter.replaceFragmetns(mViewPager, oldFragment, newFragment);

Örnek bir projeyle ilgileniyorsanız, kaynakları isteyin.


GetFragmentPosition () ve handleGetItemInbalidated () yöntemleri nasıl olmalıdır? NewFragment dönmek için getItem () güncelleyemiyorum .. Lütfen yardım edin ..

Selam! Lütfen bu bağlantıda test projesi bulun files.mail.ru/eng?back=%2FEZU6G4
AndroidTeam At Mail.Ru

1
Cihazı döndürürseniz test projeniz başarısız olur.
seb

1
@ AndroidTeamAtMail.Ru bağlantının süresi dolmuş gibi görünüyor. Lütfen kodu paylaşır mısınız
Sunny

Cevabımı görebilirsiniz . Parçaların yerini alır ve birincisine geri döner.
Lyd

4

AndroidTeam'in çözümü ile harika çalışıyor, ancak çok fazla geri dönme yeteneğine ihtiyacım olduğunu buldum.Ancak FrgmentTransaction.addToBackStack(null) sadece eklemek, Parçanın sadece ViewPager'a bildirmeden değiştirilmesine neden olacak. Sağlanan çözümü bu küçük geliştirmeyle birleştirmek, yalnızca etkinliğin onBackPressed()yöntemini geçersiz kılarak önceki duruma dönmenizi sağlar . En büyük dezavantajı, her seferinde yalnızca bir tane geri gitmesi ve birden fazla geri tıklama ile sonuçlanabilmesidir

private ArrayList<Fragment> bFragments = new ArrayList<Fragment>();
private ArrayList<Integer> bPosition = new ArrayList<Integer>();

public void replaceFragmentsWithBackOut(ViewPager container, Fragment oldFragment, Fragment newFragment) {
    startUpdate(container);

    // remove old fragment

    if (mCurTransaction == null) {
         mCurTransaction = mFragmentManager.beginTransaction();
     }
    int position = getFragmentPosition(oldFragment);
     while (mSavedState.size() <= position) {
         mSavedState.add(null);
     }

     //Add Fragment to Back List
     bFragments.add(oldFragment);

     //Add Pager Position to Back List
     bPosition.add(position);

     mSavedState.set(position, null);
     mFragments.set(position, null);

     mCurTransaction.remove(oldFragment);

     // add new fragment

     while (mFragments.size() <= position) {
         mFragments.add(null);
     }
     mFragments.set(position, newFragment);
     mCurTransaction.add(container.getId(), newFragment);

    finishUpdate(container);

    // ensure getItem returns newFragemtn after calling handleGetItemInbalidated()
    handleGetItemInvalidated(container, oldFragment, newFragment);

    container.notifyItemChanged(oldFragment, newFragment);
 }


public boolean popBackImmediate(ViewPager container){
    int bFragSize = bFragments.size();
    int bPosSize = bPosition.size();

    if(bFragSize>0 && bPosSize>0){
        if(bFragSize==bPosSize){
            int last = bFragSize-1;
            int position = bPosition.get(last);

            //Returns Fragment Currently at this position
            Fragment replacedFragment = mFragments.get(position);               
            Fragment originalFragment = bFragments.get(last);

            this.replaceFragments(container, replacedFragment, originalFragment);

            bPosition.remove(last);
            bFragments.remove(last);

            return true;
        }
    }

    return false;       
}

Umarım bu birine yardımcı olur.

Ayrıca ileriye doğru tersine getFragmentPosition()oldukça fazla getItem(). Hangi parçaların nereye gittiğini biliyorsunuz, sadece içinde olacağı doğru pozisyonu döndürdüğünüzden emin olun. İşte bir örnek:

    @Override
    protected int getFragmentPosition(Fragment fragment) {
            if(fragment.equals(originalFragment1)){
                return 0;
            }
            if(fragment.equals(replacementFragment1)){
                return 0;
            }
            if(fragment.equals(Fragment2)){
                return 1;
            }
        return -1;
    }

3

Senin içinde onCreateViewyöntemle, containeraslında bir olduğunu ViewPagerörneği.

Yani, sadece

ViewPager vpViewPager = (ViewPager) container;
vpViewPager.setCurrentItem(1);

geçerli parçanızı değiştirir ViewPager.


1
Arama saatlerinden itibaren, tüm sekmelerimin doğru çalışması için gereken tek bir kod satırı oldu. vpViewPager.setCurrentItem(1);. Nihayet sizinkine gelene kadar her seferinde hiçbir şey olmamak üzere her bir insan örneğini inceledim. Teşekkür ederim.
Brandon

1
zihin üflenir ... bu inanılmaz !! Kap değişkeninin viewpager'ın kendisi olduğunu fark etmedim. Bu cevabın önce diğer tüm uzun cevaplardan önce araştırılması gerekir. Ayrıca, Android değişkeni yapılandırma değiştiğinde varsayılan no-arg yapıcısını kullanarak parçaları otomatik olarak yeniden oluşturduğunda tüm uygulamayı basitleştiren dinleyici değişkenlerinin parça yapıcısına aktarılması yoktur.
Kevin Lee

3
bu sadece mevcut bir sekmeye değişmiyor mu? bu parçaların değiştirilmesi ile nasıl ilişkilidir?
behelit

2
@Behelit ile aynı fikirde, bu soruya cevap vermiyor, sadece ViewPagerbaşka bir sayfaya taşınacak, herhangi bir parçanın yerini almayacak.
Yoann Hercouet

2

İşte bu soruna nispeten basit çözümüm. Bu çözüm anahtarları kullanmak için vardır FragmentStatePagerAdapteryerine FragmentPagerAdaptersonradan hala örneklerini korur iken eski sizin için kullanılmayan parçalarını kaldıracak şekilde. İkincisi POSITION_NONEgetItem () işlevinin kullanılmasıdır . Parçalarımı takip etmek için basit bir Liste kullandım. Benim gereksinimim, tüm parça listesini bir kerede yeni bir listeyle değiştirmekti, ancak aşağıdakiler tek tek parçaları değiştirmek için kolayca değiştirilebilir:

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

2

Ayrıca Stacks ile çalışan bir çözüm de yaptım . Daha modüler bir yaklaşımdır, bu yüzden her parçayı ve detay parçasını belirtmeniz gerekmez FragmentPagerAdapter. ActionbarSherlock Örneği'nin üzerine kuruludur.

/**
 * 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) {
    }

}

Bu ekleme geri düğmesi sizin MainActivity işlevsellik:

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

Parça kaldırıldığında Parça Durumunu kaydetmek isterseniz . Bırakın Parçayı uygulamanızın SaveStateBundlekaydetme durumunuzla birlikte bir paket işlevine geri dönmesine izin verin . Tarafından örneklendirildikten sonra paketi alın this.getArguments().

Bunun gibi bir sekme başlatabilirsiniz :

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

u Sekme Yığını'nın üstüne bir Parça eklemek istiyorsanız benzer şekilde çalışır. Önemli : Sanırım, iki sekmenin üstünde aynı sınıftan 2 örneğe sahip olmak istemezseniz işe yaramaz. Bu çözümü hızlı bir şekilde birlikte yaptım, böylece sadece onunla herhangi bir deneyim yaşamadan paylaşabiliyorum.


Geri düğmesine basarken bir boş nokta istisnası alıyorum ve değiştirilen parçam da görünmüyor. Belki yanlış bir şey yapıyorum: parçaları doğru bir şekilde değiştirmek için doğru çağrı ne olmalı?
Jeroen

Güncelleme: İşlerin çoğunu düzelttim, ancak yeni bir parça ekledikten sonra geri düğmesine basar ve sonra başka bir sekmeye ve geri gidersem, bir boş nokta istisnası alırım. 2 sorum var: 1: bir sekmenin geçmişini nasıl kaldırabilirim ve yalnızca en son parçanın (yığının üstünde) hala mevcut olmasını nasıl sağlayabilirim? 2: nullpointer istisnasından nasıl kurtulabilirim?
Jeroen

@Jeroen 1: u mTabStackMap'ten doğru yığını alabilir ve ardından yığının üstünde yatan her TabInfo nesnesini kaldırabilir, 2: söylemesi çok zor, o zaman bulmaya çalışabileceğim yığın iziyle bir soru sor u kodunuzda bir hata olmadığından emin misiniz? Bu, u doğrudan komşulukta (sağ veya sol) bir sekmeye (ve sonra geri) geçerseniz de olur mu?
seb

Tamam, yeni bir sorunla karşılaştım: ekranımı döndürürsem, yığın tekrar boş görünüyor mu? Önceki öğelerin izini kaybetmiş gibi görünüyor ...
Jeroen

1
@seb teşekkürler. Bu kodu kullanıyordum, ancak artık bir sorun olmak üzere iç içe parçalar artık mümkün. :)
Garcon

2

Bir viewpager'da parçaların değiştirilmesi oldukça karmaşıktır, ancak çok mümkündür ve süper kaygan görünebilir. İlk olarak, görüntüleyicinin parçaların kaldırılması ve eklenmesiyle baş etmesine izin vermeniz gerekir. Olan şey, SearchFragment'ın içindeki parçayı değiştirdiğinizde, görüntüleyicinizin parça görünümlerini korur. Böylece boş bir sayfa elde edersiniz, çünkü değiştirmeye çalıştığınızda SearchFragment kaldırılır.

Çözüm, görüntüleyicinizin içinde, dışında yapılan değişiklikleri işleyecek bir dinleyici oluşturmaktır, bu nedenle önce bu kodu adaptörünüzün altına ekleyin.

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

Ardından, parçanızı değiştirmek istediğinizde dinleyici haline gelen özel bir sınıf oluşturmanız gerekir. Örneğin, böyle bir şey ekleyebilirsiniz. Yeni oluşturulan arayüzü uyguladığına dikkat edin. Bu yöntemi her çağırdığınızda, kodu aşağıdaki sınıfın içinde çalıştırır.

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

Burada belirtilmesi gereken iki ana nokta vardır:

  1. fragAt0, "esnek" bir fragmandır. Verdiğiniz parça türünü alabilir. Bu, 0 konumundaki parçayı istediğiniz parçaya değiştirirken en iyi arkadaşınız olmasını sağlar.
  2. 'NewInstance (listener) yapıcısına yerleştirilen dinleyicilere dikkat edin. Bunlar nasıl callfragment0Changed (String newFragmentIdentification) `olarak adlandırılacaksınız. Aşağıdaki kod, dinleyiciyi parçanızın içinde nasıl oluşturduğunuzu gösterir.

    statik nextFragmentListener dinleyiciArama;

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

İçindeki değişikliği arayabilirsin 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");
    }

}

Bu, parçanızı sıfır fragAt0 konumundaki yeni bir searchResultFragment olacak şekilde değiştirmek için viewpager'ınızın içindeki kodu tetikler. Vizöre işlevsel hale gelmeden önce eklemeniz gereken iki küçük parça daha var.

Bir tanesi, viewpager'ın getItem geçersiz kılma yönteminde olacaktır.

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

    }

Şimdi bu son parça olmadan hala boş bir sayfa elde edersiniz. Biraz topal, ama viewPager önemli bir parçasıdır. Viewpager'ın getItemPosition yöntemini geçersiz kılmalısınız. Normalde bu yöntem, viewpager'a her şeyi aynı tutmasını söyleyen POSITION_UNCHANGED değerini döndürür ve böylece getItem yeni parçayı sayfaya yerleştirmek için asla çağrılamaz. İşte yapabileceğiniz bir şeyin örneği

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
}

Dediğim gibi, kod çok karışıyor, ancak temelde durumunuz için özel bir adaptör oluşturmanız gerekiyor. Bahsettiğim şeyler parçayı değiştirmeyi mümkün kılacak. Muhtemelen her şeyi ıslatmak uzun zaman alacaktır, bu yüzden sabırlı olacağım, ama hepsi mantıklı olacak. Gerçekten kaygan görünümlü bir uygulama yapabildiğinden tamamen zaman ayırmaya değer.

Geri düğmesini işlemek için külçe. Bunu MainActivity'nize koydunuz

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

Fragment0changed adlı FragmentSearchResults içinde backPressed () adında bir yöntem oluşturmanız gerekir. Bu, daha önce gösterdiğim kodla birlikte geri düğmesine basmayı idare edecek. Viewpager'ı değiştirmek için kodunuzda iyi şanslar. Çok fazla iş gerektiriyor ve bulduğum kadarıyla hızlı adaptasyon yok. Dediğim gibi, temel olarak özel bir görüntüleyici adaptörü oluşturuyorsunuz ve dinleyicileri kullanarak gerekli tüm değişiklikleri yapmasına izin veriyorsunuz


Bu çözüm için teşekkürler. Ancak ekranı döndürdükten sonra herhangi bir sorun yaşadınız. Ekranı döndürdüğümde ve aynı sekmede başka bir parçayı yeniden yüklemeye çalıştığımda uygulamam kilitleniyor.
AnteGemini

Android geliştirmeyi yaptığımdan beri bir süredir, ancak tahminim, uygulamanızın artık güvenmediği bir veri parçası olması. Döndürdüğünüzde, tüm etkinlik yeniden başlatılır ve ihtiyacınız olan tüm veriler olmadan önceki durumunuzu yeniden yüklemeye çalışırsanız çökmelere neden olabilir (onPause, onResume içindeki paketten söyleyin)
user3331142 22:18

2

Bunu başarmanın yolu bu.

Her şeyden önce , düğme tıklama etkinliğini uygulamak istediğiniz Root_fragmentviewPagersekmeyi ekleyin fragment. Misal;

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

Her şeyden önce, parça değişimi RootTabFragmentiçin dahil edilmelidir 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>

Sonra, içeride RootTabFragment onCreateViewuygulamak fragmentChangeiçin sizinFirstPagerFragment

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

Bundan sonra, onClickdüğmeniz için olayı uygulayın FirstPagerFragmentve tekrar böyle bir parça değişikliği yapın.

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

Umarım bu size yardımcı olacaktır.


1

Ortada yeni parçalar eklemek veya mevcut parçayı değiştirmek isteseniz bile iyi çalışan basit bir çözüm buldum. Benim getItemId()çözümümde, her parça için benzersiz bir kimlik döndürmesi gereken geçersiz kılmalısınız. Varsayılan olarak konumlandırılmamıştır.

Var:

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

Uyarı: Bu örnekte FirstFragmentve SecondFragmentyöntemi olan soyut sınıf PageFragment'ı genişletir getPage().


1

Ben wize'ye benzer bir şey yapıyorum ama cevabımda istediğiniz zaman iki parça arasında geçiş yapabilirsiniz. Ve wize cevabı ile ekranın yönünü böyle değiştirirken bazı problemlerim var. Bu PagerAdapter şöyle görünür:

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

Adaptör kabı etkinliğinde uyguladığım dinleyici, takarken parçaya koymak için bu etkinlik:

    public class PagerContainerActivity extends AppCompatActivity implements ChangeFragmentListener {

//...

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


    }

//...
}

Daha sonra dinleyiciyi bir çağrı eklerken koymak parçası:

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

Ve son olarak dinleyici:

public interface changeFragmentListener {

    void onChange(boolean isNextFragment);

}

1

Cevapları @wize ve @mdelolmo takip ettim ve çözümü aldım. Teşekkürler Ton. Ancak, bellek tüketimini artırmak için bu çözümleri biraz ayarladım.

Gözlemlediğim sorunlar:

FragmentDeğiştirilen örneği kaydederler. Benim durumumda, tutan bir Parçadır MapViewve pahalı olduğunu düşündüm. Yani, FragmentPagerPositionChanged (POSITION_NONE or POSITION_UNCHANGED)onun yerine onun bakımını yapıyorum Fragment.

İşte benim uygulama.

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

Demo linki burada .. https://youtu.be/l_62uhKkLyM

Demo amaçlı olarak 2 parça TabReplaceFragmentve DemoTab2Fragmentikinci konumda kullanılır . Diğer tüm durumlarda DemoTabFragmentörnekleri kullanıyorum .

Açıklama:

SwitchAktiviteden Şuraya geçiyorum DemoCollectionPagerAdapter. Bu anahtarın durumuna bağlı olarak doğru parçayı göstereceğiz. Anahtar denetimi değiştirildiğinde, değişkenin değerini değiştirdiğim SwitchFragListener' onSwitchToNextFragmentyöntemini çağırıyorum . POSITION_NONE hakkında daha fazla bilgi edinin . Bu getItem geçersiz kılar ve ben orada doğru parçası örneklemek için mantık var. Üzgünüm, açıklama biraz dağınıksa.pagerAdapterPosChangedPOSITION_NONE

Orijinal fikir için @wize ve @mdelolmo'ya bir kez daha teşekkürler.

Umarım bu yardımcı olur. :)

Bu uygulamanın herhangi bir kusuru olup olmadığını bana bildirin. Bu benim projem için çok yardımcı olacak.


0

araştırmadan sonra kısa kod ile çözüm buldum. her şeyden önce parça üzerinde genel bir örnek oluşturun ve parçanın yönlendirme değişikliğinde yeniden oluşturulmaması halinde parçanızı onSaveInstanceState üzerinde kaldırın.

 @Override
public void onSaveInstanceState(Bundle outState) {
    if (null != mCalFragment) {
        FragmentTransaction bt = getChildFragmentManager().beginTransaction();
        bt.remove(mFragment);
        bt.commit();
    }
    super.onSaveInstanceState(outState);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.