Pobierz fragment z ViewPager

248

Używam ViewPagerrazem z a FragmentStatePagerAdapterdo hostowania trzech różnych fragmentów:

  • [Fragment1]
  • [Fragment2]
  • [Fragment3]

Kiedy chcę dostać Fragment1od ViewPagerw FragmentActivity.

W czym jest problem i jak go naprawić?

Qun Qin
źródło

Odpowiedzi:

504

Główna odpowiedź opiera się na nazwie generowanej przez środowisko. Jeśli to się kiedykolwiek zmieni, to przestanie działać.

Co z tym rozwiązaniem, nadpisaniem instantiateItem()i destroyItem()z Fragment(State)PagerAdapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

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

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

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(...); 
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }

    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}

Wydaje mi się, że to działa w przypadku dostępnych fragmentów. Fragmenty, które nie zostały jeszcze utworzone, zwracają wartość NULL podczas wywoływania getRegisteredFragment. Ale używałem tego głównie, aby wyciągnąć prąd Fragmentz ViewPager: adapater.getRegisteredFragment(viewPager.getCurrentItem())i to nie wróci null.

Nie znam żadnych innych wad tego rozwiązania. Jeśli są, chciałbym wiedzieć.

Streets Of Boston
źródło
41
To najlepsze rozwiązanie, jakie mogę wymyślić. Jedyną sugestią byłoby być może owinięcie Fragmentw, WeakReferenceaby zagwarantować, że nie zapobiegniesz zbieraniu zniszczonego fragmentu? Wydaje się, że to właściwa rzecz ...
Alex Lockwood,
7
Co się stanie, gdy MyPagerAdapterzostanie zniszczony z powodu cyklu życia (tj. Obracania), nie registerdFragmentszostanie utracony? Czy użytkownik Activity/ Fragmentusing będzie MyPagerAdaptermusiał go zapisać onSaveInstanceState, a następnie będzie musiał zaktualizować go o nowy numer FragmentManagerreferencyjny?
Steven Byle
10
Jeśli się nie mylę (i powinieneś to sprawdzić), metoda getItem nie jest wywoływana - jak wiadomo - ale metoda instantiateItem jest wywoływana dla każdego fragmentu, który jest przywracany przez strukturę po obrocie.
Streets Of Boston
6
Tak, sprawdziłem, że getItemnie jest wywoływane ponownie przy obracaniu (dla wszystkich fragów, które już zostały utworzone), ponieważ FragmentManagerprzywraca stany, Fragmentsktóre utrzymuje w pager. Jeśli instantiateItemzostanie wywołane po Fragmentprzywróceniu każdego z nich , wówczas to rozwiązanie jest w rzeczywistości bezpieczniejsze i bardziej przyszłościowe niż moje lub zaakceptowana odpowiedź. Zastanowię się nad próbowaniem tego sam.
Steven Byle
6
@Dori Nie łamie tego. Moje rozwiązanie nie wykorzystuje wyniku wywołania „getItem ()”. Zamiast tego wykorzystuje wynik zapisany z wywołania „instantiateItem ()”. A cykl życia fragmentu nie jest zepsuty, ponieważ zapisany fragment zostanie usunięty z rzadkiej tablicy przy wywołaniu „destroyItem ()”.
Streets Of Boston
85

Aby pobrać fragmenty z ViewPager, istnieje wiele odpowiedzi tutaj i na innych powiązanych wątkach / blogach SO. Wszyscy, których widziałem, są załamani i ogólnie wydają się należeć do jednego z dwóch wymienionych poniżej typów. Są też inne ważne rozwiązania, jeśli tylko chcą chwycić bieżącego fragmentu, jak to inna odpowiedź na tego wątku.

Jeśli używasz, FragmentPagerAdapterpatrz poniżej. Jeśli korzystasz, FragmentStatePagerAdapterwarto na to spojrzeć . Indeksy chwytania, które nie są bieżące w FragmentStateAdapter, nie są tak przydatne, ponieważ ze względu na swój charakter zostaną całkowicie zerwane, zniknęły z widoku / poza granicami offScreenLimit.

NIEBEZPIECZNE ŚCIEŻKI

Źle: prowadź własną wewnętrzną listę fragmentów, dodawaną, kiedy FragmentPagerAdapter.getItem()zostanie wywołana

  • Zwykle za pomocą a SparseArraylubMap
  • Nie jest to jeden z wielu przykładów, które widziałem w opisach zdarzeń cyklu życia, więc to rozwiązanie jest kruche. Tak jak getItemnazywa się to tylko przy pierwszym przewinięciu strony do (lub uzyskaniu, jeśli twoje ViewPager.setOffscreenPageLimit(x)> 0) w ViewPager, jeśli hosting Activity/ Fragmentzostanie zabity lub zrestartowany, wewnętrzny SpaseArrayzostanie usunięty po odtworzeniu niestandardowego FragmentPagerActivity, ale za kulisami ViewPagers wewnętrzne fragmenty zostaną odtworzone, i getItembędzie nie być nazywany dla każdego z indeksów, więc zdolność do uzyskania fragmentu z indeksu zostaną utracone na zawsze. Można wyjaśnić to zapisując się i przywracania tych fragmentów poprzez referencje FragmentManager.getFragment(), a putFragmentjednak ten rozpoczyna się bałagan IMHO.

Źle: Stwórz własny identyfikator tagu pasujący do tego, co jest używane pod maskąFragmentPagerAdapter i użyj tego, aby pobrać fragmenty strony zFragmentManager

  • Jest to o tyle lepsze, że radzi sobie z problemem utraty fragmentów referencji w pierwszym rozwiązaniu z macierzą wewnętrzną, ale jak słusznie wskazano w odpowiedziach powyżej i gdzie indziej w sieci - wydaje się hacką, ponieważ jest to prywatna metoda wewnętrzna, ViewPagerktóra mogłaby zmienić w dowolnym momencie lub dla dowolnej wersji systemu operacyjnego.

Metodą odtworzoną dla tego rozwiązania jest

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

SZCZĘŚLIWA ŚCIEŻKA: ViewPager.instantiateItem()

Podejście podobne do getItem()powyższego, ale bez przerywania cyklu życia, polega na przyłączeniu się do instantiateItem()niego, getItem()ponieważ to pierwsze będzie wywoływane za każdym razem, gdy indeks jest tworzony / dostępny. Zobacz tę odpowiedź

SZCZĘŚLIWA ŚCIEŻKA: Zbuduj własną FragmentViewPager

Zbuduj własną FragmentViewPagerklasę ze źródła najnowszej biblioteki wsparcia i zmień metodę używaną wewnętrznie do generowania znaczników fragmentu. Możesz go zastąpić poniższym. Ma to tę zaletę, że wiesz, że tworzenie tagów nigdy się nie zmieni i nie polegasz na prywatnym API / metodzie, co zawsze jest niebezpieczne.

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

Następnie, jak mówi doktor, gdy chcesz pobrać fragment używany do indeksu, po prostu wywołaj coś takiego jak ta metoda (którą możesz umieścić w niestandardowej FragmentPagerAdapterlub podklasie), mając świadomość, że wynik może być zerowy, jeśli getItem nie został jeszcze wywołany ta strona, tj. nie została jeszcze utworzona.

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

Jest to proste rozwiązanie, które rozwiązuje problemy z dwoma pozostałymi rozwiązaniami znajdowanymi wszędzie w Internecie

Dori
źródło
6
To zadziała, ale wymaga skopiowania klasy ViewPager do własnego kodu źródłowego. Poleganie na „instantiateItem ()” i „destroyItem ()” adaptera pagera ViewPager będzie działał i będzie honorował cykle życia fragmentów (te dwie metody są wywoływane również, gdy fragmenty są tworzone ze stanu zapisanej instancji). Masz rację, że poleganie na wywołaniu metody „getItem ()” nie jest dobrym pomysłem, a używanie prywatnych interfejsów API również nie jest.
Streets Of Boston
+1 Zgadzam się, że to także rozwiązanie i edytowałem powyżej. Jedyną różnicą jest to, że powyższe działa w jeszcze jednym przypadku użycia, instantiateItem()który ma miejsce, gdy chcesz uzyskać dostęp do fragmentu, który nie był jeszcze odwiedzany po zdarzeniu cyklu życia i był odwiedzany przed zdarzeniem cyklu życia. Mała różnica, którą znam, ale ta, która doprowadziła do subtelnego błędu w moim programie, dlatego patrzę na to.
Dori
Jeśli setOffscreenPageLimit = 1 (domyślnie), FragmentStatePageAdapter zacznie zamieniać fragmenty do i z pamięci podczas dostępu do stron. Następnie przez wywołanie getItem () zostanie utworzone nowe wystąpienie ponownie odwiedzonych stron / fragmentów. Czy po takiej ponownej wizycie system może nakazać systemowi wznowienie wcześniej utworzonych instancji zamiast tworzenia nowej?
carl
jeśli przekroczy limit strony, będzie musiał utworzyć nowy - ale przechodząc w stan zapisany. Jeśli chcesz zachować stare, możesz zwiększyć limit stron
Dori
@Dori nie ma w getItemId(pos)środkuFragmentStatePagerAdapter
Jemshit Iskenderov
70

Dodaj kolejne metody do FragmentPagerAdapter:

public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return  mFragmentManager.findFragmentByTag(name);
}

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

getActiveFragment (0) musi działać.

Oto rozwiązanie zaimplementowane w ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Jeśli coś zawiedzie, zobaczysz dobry dziennik awarii.

kzotin
źródło
Wielkie dzięki:) . Za pomocą podciągnąłem go w inny sposób, za pomocą modułu obsługi, aby opublikować fragment. Nie jest to zbyt odpowiednie, ale w końcu rozwiązało problem. Nawiasem mówiąc, jesteś miły :)
Qun Qin
12
Korzystałem z tej metody, ale uważam, że przestała działać po przejściu na API 17 (?). Poleciłbym inną metodę i wolałbym ją, gdyby Google po prostu opublikował API do pobierania fragmentu z ViewPager, biorąc pod uwagę jego pozycję.
gcl1
mam problem z wywołaniem drugiego fragmentu, metoda tworzy nowy
Vasil Valchev
2
Ponieważ niektóre wersje interfejsu API metody makeFragmentName zostały zmienione na prywatny statyczny ciąg makeFragmentName (int viewId, long id) {return "android: switcher:" + viewId + ":" + id; } więc metoda getActiveFragment powinna teraz wyglądać tak (użyj getItemId zamiast pozycji dla drugiego argumentu) public Fragment getActiveFragment (kontener ViewPager, pozycja int) {String name = makeFragmentName (container.getId (), getItemId (pozycja)); return mFragmentManager.findFragmentByTag (nazwa); }
Eugene Popovich
1
To naprawdę działa, ale jest naprawdę niebezpieczne, ponieważ polega na wewnętrznej implementacji pagera widokowego i jeśli Google zmieni implementację (i może) mogą się zdarzyć złe rzeczy. Naprawdę mam nadzieję, że goole udostępni go, aby uzyskać fragment na żywo
shem,
38

Kolejne proste rozwiązanie:

    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }
Mindphaser
źródło
1
To wydaje się idealne dla moich obecnych potrzeb fragmentów.
danny117
Jeśli wszystko, co musisz zrobić, to pobrać aktualnie wybrany Fragment, to wszystko, czego potrzebujesz - metoda setPrimaryItem jest ustawiana przy dołączaniu, a także przy każdej aktualizacji wewnętrznego zestawu Fragmentu jako bieżący element.
Graeme,
1
To brzmi jak dobre rozwiązanie, ale jak setPrimaryItem()się nazywa po tym, ViewPager.OnPageChangeListener#onPageSelected() że nie mogę go użyć :-(
hardysim
21

Wiem, że to ma kilka odpowiedzi, ale może to komuś pomoże. Użyłem stosunkowo prostego rozwiązania, gdy potrzebowałem uzyskać Fragmentod siebie ViewPager. W twojej Activitylub Fragmentgospodarstwa ViewPager, można użyć tego kodu, aby przejść przez każdy Fragmentgo posiada.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
    if(viewPagerFragment != null) {
        // Do something with your Fragment
        // Check viewPagerFragment.isResumed() if you intend on interacting with any views.
    }
}
  • Jeśli znasz swoją pozycję Fragmentw ViewPager, możesz po prostu zadzwonić getItem(knownPosition).

  • Jeśli nie wiesz na pozycję Fragmentw ViewPager, można mieć dzieci Fragmentszaimplementować interfejs z metodą jak getUniqueId()i używać, aby je odróżnić. Możesz też przewijać wszystkie Fragmentsi sprawdzać typ klasy, npif(viewPagerFragment instanceof FragmentClassYouWant)

!!! EDYTOWAĆ !!!

Odkryłem, że getItemwywoływany jest tylko FragmentPagerAdapterwtedy, gdy każdy Fragmentmusi zostać utworzony za pierwszym razem , potem wydaje się, że Fragmentssą one przetwarzane za pomocą FragmentManager. W ten sposób wiele implementacji FragmentPagerAdaptertworzy nowe Fragment s w getItem. Używając mojej powyższej metody, oznacza to, że będziemy tworzyć nowe Fragments za każdym razem, gdy getItemzostanie wywołane, gdy przejdziemy przez wszystkie elementy w FragmentPagerAdapter. Z tego powodu znalazłem lepsze podejście, używając zamiast tego FragmentManagerkażdego z nich Fragment(używając zaakceptowanej odpowiedzi). To jest bardziej kompletne rozwiązanie i działało dla mnie dobrze.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    String name = makeFragmentName(mViewPager.getId(), i);
    Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
    // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
    if(viewPagerFragment != null) {

        // Do something with your Fragment
        if (viewPagerFragment.isResumed()) {
            // Interact with any views/data that must be alive
        }
        else {
            // Flag something for update later, when this viewPagerFragment
            // returns to onResume
        }
    }
}

Będziesz potrzebował tej metody.

private static String makeFragmentName(int viewId, int position) {
    return "android:switcher:" + viewId + ":" + position;
}
Steven Byle
źródło
1
Po prostu findFragmentByTag (), ale gdzie moglibyśmy ustawić TAG z fragmentem?
VinceStyling
@vince ViewPagerSam ustawia te tagi. To rozwiązanie jest kruche, ponieważ polega na znajomości „ukrytej” konwencji nazewnictwa ViewPager. Odpowiedź na ulice Bostonu to znacznie bardziej kompleksowe rozwiązanie, którego teraz używam w swoim projekcie (zamiast tego podejścia).
Steven Byle
To działa świetnie! Ale usunąłem warunek „if (viewPagerFragment.isResumed ())”, ponieważ muszę zaktualizować moje strony ListFragment, które są poza ekranem. Następnie, gdy użytkownik powraca do strony ListFragment, wszystko jest aktualizowane o nowe dane.
JDJ
10

W moim przypadku żadne z powyższych rozwiązań nie zadziałało.

Ponieważ jednak używam menedżera fragmentów potomnych w fragmencie, użyto następujących elementów:

Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());

Działa to tylko wtedy, gdy twoje fragmenty w Menedżerze odpowiadają elementowi przeglądarki.

Veedka
źródło
Jest to idealna odpowiedź na pobranie starych fragmentów z pagera widokowego podczas odtwarzania aktywności lub fragmentu.
Smeet,
7

Aby uzyskać bieżący widoczny fragment z ViewPager . Używam tego prostego stwierdzenia i działa dobrze.

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }
Zar E Ahmer
źródło
3

Poradziłem sobie z tym, tworząc najpierw listę wszystkich fragmentów ( List<Fragment> fragments;), których zamierzałem użyć, a następnie dodałem je do pagera, aby ułatwić obsługę aktualnie oglądanego fragmentu.

Więc:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

więc można to nazwać:

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

więc mogłem wrzucić go do instrukcji if, która działałaby tylko wtedy, gdyby znajdowała się we właściwym fragmencie

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

ale to tylko moje podejście do hack and slash, ale zadziałało dla mnie, używam go, wprowadzam zmiany w moim aktualnie wyświetlanym fragmencie, gdy przycisk Wstecz jest wciśnięty.

Russell Cargill
źródło
1
najlepsza odpowiedź dla mnie
Sonu Kumar
3

Jest to oparte na powyższej odpowiedzi Stevena. Zwróci to faktyczną instancję fragmentu, który jest już dołączony do działania nadrzędnego.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }
Drzewo pomarańczowe
źródło
2

Nie mogłem znaleźć prostego, czystego sposobu na zrobienie tego. Widżet ViewPager to jednak kolejna grupa ViewGroup, w której przechowywane są Twoje fragmenty. ViewPager ma te fragmenty jako bezpośrednie dzieci. Możesz więc po prostu iterować nad nimi (używając .getChildCount () i .getChildAt ()) i sprawdzić, czy szukana instancja fragmentu jest aktualnie załadowana do ViewPager i uzyskaj odniesienie do niej. Np. Możesz użyć statycznego unikalnego pola ID, aby rozdzielić fragmenty.

Zauważ, że ViewPager mógł nie załadować szukanego fragmentu, ponieważ jest to wirtualny kontener, taki jak ListView.

Zsombor Erdődy-Nagy
źródło
1
Dzięki za odpowiedź, odzyskuję ją za pomocą adpter.getItem (); Jestem studentem pierwszego roku w programowaniu na Androida. naprawdę cię doceniam. Teraz mogę pobrać ListFragment i chcę dodać do niego stopkę. Podczas gdy robię to w mojej działalności, logcat drukuje: „java.lang.IllegalStateException: Widok zawartości jeszcze nie. Utworzony”. Wiem dlaczego, ale mam trudności z radzeniem sobie z tym.
Qun Qin
1
FragmentActivity ma metodę onAttachFragment (), dozować tę pracę do zawartości fragmentu ViewPager odrobiną?
Vasil Valchev
2

FragmentPagerAdapter to fabryka fragmentów. Aby znaleźć fragment na podstawie jego pozycji, jeśli nadal jest w pamięci, użyj tego:

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

Przykładowy kod interfejsu API obsługi v4.

Daniel De León
źródło
Zwraca null w onresume (). Masz pomysł, dlaczego i jak to naprawić?
wydaje się
2

ty musisz wywoływać getItem()ani żadnej innej metody na późniejszym etapie, aby uzyskać referencję Fragmenthostowanego obiektu ViewPager. Jeśli chcesz zaktualizować niektóre dane w środku, Fragmentskorzystaj z tego podejścia: dynamicznie aktualizować ViewPager?

Kluczem jest ustawienie nowych danych w środku Adaperi połączenie, notifyDataSetChanged()które z kolei zadzwoni getItemPosition(), przekazując ci referencjeFragment i dając szansę na ich aktualizację. Wszystkie inne sposoby wymagają zachowania odniesienia do siebie lub innego hacka, co nie jest dobrym rozwiązaniem.

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(xyzData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}
M-WaJeEh
źródło
Nie rozumiem tutaj, potrzebujesz referencji do Fragmentu, aby użyć getItemPosition (), więc równie dobrze możesz nie używać getItemPosition, co?
getItemPosition()jest metodą w twoim adapterze. Nie zadzwonisz bezpośrednio. Posiadasz numer referencyjny adaptera, więc dzwonisz, adapter.notifyDataSetChanged()który z kolei wywoła getItemPosition()adapter, przekazując numer referencyjny twojego adaptera Fragment. Możesz zobaczyć pełną implementację w akcji tutaj stackoverflow.com/questions/19891828/…
M-WaJeEh,
Przeczytałem to i wciąż nie rozumiem. Nadal potrzebujesz bezpośredniego odniesienia do tych fragmentów, aby wykonywać połączenia przeciwko nim, prawda? Wspominasz o tym jako hack, ale nie widzę alternatywy; adapter.getItem (i) oczywiście nie zadziała.
2
Ok zaktualizowałem swoją odpowiedź, aby wyjaśnić więcej. Oczywiście potrzebne jest odniesienie, aby zaktualizować, Fragmentale sposób uzyskania odniesienia jest dyskusyjny. Inne rozwiązania uzyskują referencje FragmentManagerprzy użyciu łańcucha podobnego "android:switcher:"+idlub powracającego POSITION_NONEz getItemosition()powodu spowodowania odtworzenia wszystkich fragmentów.
M-WaJeEh,
Dzięki, to ma o wiele więcej sensu i pasuje do mojego doświadczenia (więc mogę nie robić czegoś złego, ha).
2

Musi rozszerzyć FragmentPagerAdaptersię na klasę adaptera ViewPager.
Jeśli używasz FragmentStatePagerAdapterwtedy nie będzie w stanie znaleźć Fragmentprzez jegoID

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

Jak korzystać z tej metody: -

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;
mahesh_babariya
źródło
2

Hej, odpowiedziałem na to pytanie tutaj . Zasadniczo musisz zastąpić

public Object instantiateItem (kontener ViewGroup, pozycja int)

Metoda FragmentStatePagerAdapter.

Utkarsh Saxena
źródło
1

Najlepszym rozwiązaniem jest użycie rozszerzenia, które stworzyliśmy w CodePath o nazwie SmartFragmentStatePagerAdapter . Zgodnie z tym przewodnikiem znacznie ułatwia pobieranie fragmentów i aktualnie wybranego fragmentu z ViewPager. Lepsze jest także zarządzanie pamięcią fragmentów osadzonych w adapterze.

Nathan
źródło
0

Najłatwiejszy i najbardziej zwięzły sposób. Jeśli wszystkie twoje fragmenty ViewPagernależą do różnych klas, możesz je odzyskać i rozróżnić w następujący sposób:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}
riwnodennyk
źródło
Jest to również błędne, ponieważ istnieje wiele fragmentów, które dołączają się podczas korzystania z ViewPager. jest obecny fragment strony, a jeden po jego lewej i jeden po prawej. Umożliwia to użytkownikowi przesuwanie się między nimi bez konieczności inicjowania ich tylko wtedy, gdy użytkownik do nich dotrze.
programista Androida
0

Zaimplementowałem to łatwe z nieco innym podejściem.

Moja niestandardowa metoda FragmentAdapter.getItem nie zwróciła nowej MyFragment (), ale instancję MyFragment, która została utworzona w konstruktorze FragmentAdapter.

Następnie w swojej działalności pobrałem fragment z adaptera, sprawdź, czy jest to instancja Potrzebny fragment, a następnie rzutuj i użyj potrzebnych metod.

lxknvlk
źródło
0

Utwórz identyfikator zasobu całkowitego w /values/integers.xml

<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>

Następnie w funkcji getItem PagerAdapter:

public Fragment getItem(int position) {

        Fragment fragment = null;

        if (position == 0) {
            fragment = FragmentOne.newInstance();
            mViewPager.setTag(R.integer.page1,fragment);

        }
        else if (position == 1) {

            fragment = FragmentTwo.newInstance();
            mViewPager.setTag(R.integer.page2,fragment);

        } else if (position == 2) {

            fragment = FragmentThree.newInstance();
            mViewPager.setTag(R.integer.page3,fragment);

        }

        return fragment;
        }

Następnie w działaniu napisz tę funkcję, aby uzyskać odwołanie do fragmentu:

private Fragment getFragmentByPosition(int position) {
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = (Fragment) mViewPager.getTag(R.integer.page1);
            break;

        case 1:

            fragment = (Fragment) mViewPager.getTag(R.integer.page2);
            break;

        case 2:
            fragment = (Fragment) mViewPager.getTag(R.integer.page3);
            break;
            }

            return fragment;
    }

Uzyskaj odwołanie do fragmentu, wywołując powyższą funkcję, a następnie rzutuj na niestandardowy fragment:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }
użytkownik2574090
źródło
0

Łatwy sposób na iterację fragmentów w menedżerze fragmentów. Znajdź viewpager, który ma argument pozycji sekcji, umieszczony w publicznym statycznym PlaceholderFragment newInstance (int sectionNumber) .

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}
Evgeny
źródło
0

We fragmencie

public int getArgument(){
   return mPage;
{
public void update(){

}

W FragmentActivity

List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
    if((f instanceof PageFragment)&&(!f.isDetached())){
          PageFragment pf = (PageFragment)f;   
          if(pf.getArgument()==pager.getCurrentItem())pf.update();
    }
}
Mark Zhuravlyov
źródło
0

w TabLayout jest wiele zakładek dla Fragmentu. fragment można znaleźć według Tagu, korzystając z indeksu fragmentu.

Np. indeks dla Fragment1 wynosi 0, więc w findFragmentByTag()metodzie przekaż znacznik dla Viewpager. po użyciu fragmentTransaction możesz dodać, zastąp fragment.

String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);

SUMIT MONAPARA
źródło
-1

Ok dla adaptera FragmentStatePagerAdapter finansuję rozwiązanie:

w twoim FragmentActivity:

ActionBar mActionBar = getSupportActionBar(); 
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));

viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);

i utwórz metodę w swojej klasie FragmentActivity - Aby ta metoda dała Ci dostęp do Twojego Fragmentu, wystarczy nadać mu pozycję żądanego fragmentu:

public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}

w twoim adapterze:

public class MyPagerAdapter extends FragmentStatePagerAdapter {

private final ActionBar actionBar;
private final FragmentManager fragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}

@Override
public int getCount() {
return this.actionBar.getTabCount();
}

@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}

private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}

}
douarbou
źródło
-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

indexjest miejscem fragmentu w adapterze, który dodałeś jako fragment1pierwszy, więc fragment1przekaż ponownie indexjako 0 i tak dalej dla odpoczynku

Wisznu Prasad
źródło