Używam ViewPager
razem z a FragmentStatePagerAdapter
do hostowania trzech różnych fragmentów:
- [Fragment1]
- [Fragment2]
- [Fragment3]
Kiedy chcę dostać Fragment1
od ViewPager
w FragmentActivity
.
W czym jest problem i jak go naprawić?
Używam ViewPager
razem z a FragmentStatePagerAdapter
do hostowania trzech różnych fragmentów:
Kiedy chcę dostać Fragment1
od ViewPager
w FragmentActivity
.
W czym jest problem i jak go naprawić?
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 Fragment
z 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ć.
Fragment
w,WeakReference
aby zagwarantować, że nie zapobiegniesz zbieraniu zniszczonego fragmentu? Wydaje się, że to właściwa rzecz ...MyPagerAdapter
zostanie zniszczony z powodu cyklu życia (tj. Obracania), nieregisterdFragments
zostanie utracony? Czy użytkownikActivity
/Fragment
using będzieMyPagerAdapter
musiał go zapisaćonSaveInstanceState
, a następnie będzie musiał zaktualizować go o nowy numerFragmentManager
referencyjny?getItem
nie jest wywoływane ponownie przy obracaniu (dla wszystkich fragów, które już zostały utworzone), ponieważFragmentManager
przywraca stany,Fragments
które utrzymuje w pager. JeśliinstantiateItem
zostanie wywołane poFragment
przywró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.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,
FragmentPagerAdapter
patrz poniżej. Jeśli korzystasz,FragmentStatePagerAdapter
warto 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łanaSparseArray
lubMap
getItem
nazywa się to tylko przy pierwszym przewinięciu strony do (lub uzyskaniu, jeśli twojeViewPager.setOffscreenPageLimit(x)
> 0) wViewPager
, jeśli hostingActivity
/Fragment
zostanie zabity lub zrestartowany, wewnętrznySpaseArray
zostanie usunięty po odtworzeniu niestandardowego FragmentPagerActivity, ale za kulisami ViewPagers wewnętrzne fragmenty zostaną odtworzone, igetItem
bę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 referencjeFragmentManager.getFragment()
, aputFragment
jednak 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
ViewPager
która mogłaby zmienić w dowolnym momencie lub dla dowolnej wersji systemu operacyjnego.Metodą odtworzoną dla tego rozwiązania jest
SZCZĘŚLIWA ŚCIEŻKA:
ViewPager.instantiateItem()
Podejście podobne do
getItem()
powyższego, ale bez przerywania cyklu życia, polega na przyłączeniu się doinstantiateItem()
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ą
FragmentViewPager
klasę 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.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
FragmentPagerAdapter
lub 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.Jest to proste rozwiązanie, które rozwiązuje problemy z dwoma pozostałymi rozwiązaniami znajdowanymi wszędzie w Internecie
źródło
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.getItemId(pos)
środkuFragmentStatePagerAdapter
Dodaj kolejne metody do FragmentPagerAdapter:
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.
źródło
Kolejne proste rozwiązanie:
źródło
setPrimaryItem()
się nazywa po tym,ViewPager.OnPageChangeListener#onPageSelected()
że nie mogę go użyć :-(Wiem, że to ma kilka odpowiedzi, ale może to komuś pomoże. Użyłem stosunkowo prostego rozwiązania, gdy potrzebowałem uzyskać
Fragment
od siebieViewPager
. W twojejActivity
lubFragment
gospodarstwaViewPager
, można użyć tego kodu, aby przejść przez każdyFragment
go posiada.Jeśli znasz swoją pozycję
Fragment
wViewPager
, możesz po prostu zadzwonićgetItem(knownPosition)
.Jeśli nie wiesz na pozycję
Fragment
wViewPager
, można mieć dzieciFragments
zaimplementować interfejs z metodą jakgetUniqueId()
i używać, aby je odróżnić. Możesz też przewijać wszystkieFragments
i sprawdzać typ klasy, npif(viewPagerFragment instanceof FragmentClassYouWant)
!!! EDYTOWAĆ !!!
Odkryłem, że
getItem
wywoływany jest tylkoFragmentPagerAdapter
wtedy, gdy każdyFragment
musi zostać utworzony za pierwszym razem , potem wydaje się, żeFragments
są one przetwarzane za pomocąFragmentManager
. W ten sposób wiele implementacjiFragmentPagerAdapter
tworzy noweFragment
s wgetItem
. Używając mojej powyższej metody, oznacza to, że będziemy tworzyć noweFragment
s za każdym razem, gdygetItem
zostanie wywołane, gdy przejdziemy przez wszystkie elementy wFragmentPagerAdapter
. Z tego powodu znalazłem lepsze podejście, używając zamiast tegoFragmentManager
każdego z nichFragment
(używając zaakceptowanej odpowiedzi). To jest bardziej kompletne rozwiązanie i działało dla mnie dobrze.Będziesz potrzebował tej metody.
źródło
ViewPager
Sam ustawia te tagi. To rozwiązanie jest kruche, ponieważ polega na znajomości „ukrytej” konwencji nazewnictwaViewPager
. Odpowiedź na ulice Bostonu to znacznie bardziej kompleksowe rozwiązanie, którego teraz używam w swoim projekcie (zamiast tego podejścia).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.
źródło
źródło
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:
więc można to nazwać:
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
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.
źródło
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.
źródło
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.
źródło
FragmentPagerAdapter to fabryka fragmentów. Aby znaleźć fragment na podstawie jego pozycji, jeśli nadal jest w pamięci, użyj tego:
Przykładowy kod interfejsu API obsługi v4.
źródło
ty musisz wywoływać
getItem()
ani żadnej innej metody na późniejszym etapie, aby uzyskać referencjęFragment
hostowanego obiektuViewPager
. Jeśli chcesz zaktualizować niektóre dane w środku,Fragment
skorzystaj z tego podejścia: dynamicznie aktualizować ViewPager?Kluczem jest ustawienie nowych danych w środku
Adaper
i połączenie,notifyDataSetChanged()
które z kolei zadzwonigetItemPosition()
, 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.źródło
getItemPosition()
jest metodą w twoim adapterze. Nie zadzwonisz bezpośrednio. Posiadasz numer referencyjny adaptera, więc dzwonisz,adapter.notifyDataSetChanged()
który z kolei wywołagetItemPosition()
adapter, przekazując numer referencyjny twojego adapteraFragment
. Możesz zobaczyć pełną implementację w akcji tutaj stackoverflow.com/questions/19891828/…Fragment
ale sposób uzyskania odniesienia jest dyskusyjny. Inne rozwiązania uzyskują referencjeFragmentManager
przy użyciu łańcucha podobnego"android:switcher:"+id
lub powracającegoPOSITION_NONE
zgetItemosition()
powodu spowodowania odtworzenia wszystkich fragmentów.Musi rozszerzyć
FragmentPagerAdapter
się na klasę adaptera ViewPager.Jeśli używasz
FragmentStatePagerAdapter
wtedy nie będzie w stanie znaleźćFragment
przez jegoID
Jak korzystać z tej metody: -
źródło
Hej, odpowiedziałem na to pytanie tutaj . Zasadniczo musisz zastąpić
Metoda FragmentStatePagerAdapter.
źródło
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.
źródło
Najłatwiejszy i najbardziej zwięzły sposób. Jeśli wszystkie twoje fragmenty
ViewPager
należą do różnych klas, możesz je odzyskać i rozróżnić w następujący sposób:źródło
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.
źródło
Utwórz identyfikator zasobu całkowitego w /values/integers.xml
Następnie w funkcji getItem PagerAdapter:
Następnie w działaniu napisz tę funkcję, aby uzyskać odwołanie do fragmentu:
Uzyskaj odwołanie do fragmentu, wywołując powyższą funkcję, a następnie rzutuj na niestandardowy fragment:
źródło
Ł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) .
źródło
We fragmencie
W FragmentActivity
źródło
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);
źródło
Ok dla adaptera
FragmentStatePagerAdapter
finansuję rozwiązanie:w twoim FragmentActivity:
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:
w twoim adapterze:
źródło
index
jest miejscem fragmentu w adapterze, który dodałeś jakofragment1
pierwszy, więcfragment1
przekaż ponownieindex
jako 0 i tak dalej dla odpoczynkuźródło