Poniżej znajduje się mój kod, z którego 3 Fragment classes
każdy jest osadzony na każdej z 3 zakładek ViewPager
. Mam opcję menu. Jak pokazano w onOptionsItemSelected()
, wybierając opcję, muszę zaktualizować fragment, który jest obecnie widoczny. Aby to zaktualizować, muszę wywołać metodę z klasy fragmentów. Czy ktoś może zasugerować, jak wywołać tę metodę?
public class MainActivity extends ActionBarActivity {
ViewPager ViewPager;
TabsAdapter TabsAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewPager = new ViewPager(this);
ViewPager.setId(R.id.pager);
setContentView(ViewPager);
final ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Attaching the Tabs to the fragment classes and setting the tab title.
TabsAdapter = new TabsAdapter(this, ViewPager);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
FragmentClass1.class, null);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
FragmentClass2.class, null);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
FragmentClass3.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addText:
**// Here I need to call the method which exists in the currently visible Fragment class**
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
}
public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
tabPosition = tab.getPosition();
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public int getCount() {
return mTabs.size();
}
}
}
Załóżmy, że poniżej znajduje się klasa fragmentów z metodą, updateList()
którą chcę wywołać:
public class FragmentClass1{
ArrayList<String> originalData;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.frag1, container, false);
originalData = getOriginalDataFromDB();
return fragmentView;
}
public void updateList(String text)
{
originalData.add(text);
//Here I could do other UI part that need to added
}
}
Odpowiedzi:
Prostym sposobem na to jest użycie triku związanego z
FragmentPagerAdapter
implementacją:Proszę przemyśleć konwencję nazewnictwa zmiennych, używając jako nazwy zmiennej nazwy klasy bardzo mylące (więc nie
ViewPager ViewPager
, użyjViewPager mPager
na przykład).źródło
instantiateItem()
metody i samodzielne uzyskanie referencji do odpowiednich fragmentów.mAdapter.getItem(position)
niesamowitego ... Przynajmniej teraz wiem, że inne próby 8512 nie zadziałały. Dziękiźródło
onPageSelected
/onPageDeselected
i wszystkie moje fragmenty pagera go rozszerzają. NastępniesetPrimaryitem
może odpowiednio wywołać te metody, gdy użytkownik przesunie się na nową stronę. Oznacza to, że możesz wdrożyć leniwszą strategię ładowania danych na stronach, które nawet nie są wyświetlane. Należy jednak pamiętać, że podczas przenoszenia strony lepiej wygląda, jeśli następna strona jest już zapełniona danymi, więc leniwe ładowanie wszystkich danychonPageSelected
może nie być idealne.if
oświadczenie? Fragment po prostu wywołujeequals
metodę obiektu, czyli płytkie porównanie. Dlaczego więc nie zawsze dzwonićmCurrentFragment = ((Fragment) object);
?Przede wszystkim śledź wszystkie „aktywne” fragmenty stron. W takim przypadku śledzisz strony fragmentów w FragmentStatePagerAdapter, który jest używany przez ViewPager.
Aby uniknąć utrzymywania odniesienia do „nieaktywnych” stron fragmentów, musisz zaimplementować metodę destroyItem (...) FragmentStatePagerAdapter:
a kiedy musisz uzyskać dostęp do aktualnie widocznej strony, zadzwoń:
Gdzie metoda getFragment (int) MyAdapter wygląda następująco:
Mam nadzieję, że to może pomóc!
źródło
Jest to jedyny sposób, w jaki nie otrzymuję NullPointerException dla zmiennych instancji tej konkretnej klasy fragmentu. Może to być pomocne dla innych, którzy utknęli przy tym samym. W onOptionsItemSelected () kodowałem poniżej:
źródło
FragmentStatePagerAdapter
bez zastępowania żadnego kodu. W rzeczywistości powinna być tak prosta, jak funkcja po prostu powracaviewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem())
.FragmentStatePagerAdapter ma metodę publiczną o nazwie instantiateItem, która zwraca fragment na podstawie określonych wartości parametrów, ta metoda ma dwa parametry ViewGroup (ViewPager) i pozycję.
Użyłem tej metody, aby uzyskać fragment określonej pozycji,
źródło
Wiem, że jest za późno, ale mam naprawdę proste sposoby, aby to zrobić,
// dla fragmentu przy 0 pozycjach
źródło
Jest tu wiele odpowiedzi, które tak naprawdę nie odnoszą się do podstawowego faktu, że tak naprawdę NIE MA SPOSOBU, aby to zrobić w sposób przewidywalny, i w sposób, który nie spowoduje, że w pewnym momencie w przyszłości strzelisz sobie w stopę.
FragmentStatePagerAdapter
jest jedyną klasą, która wie, jak niezawodnie uzyskać dostęp do fragmentów, które są śledzone przezFragmentManager
- każda próba odgadnięcia identyfikatora lub tagu fragmentu nie jest wiarygodna, długoterminowa. Próby ręcznego śledzenia instancji prawdopodobnie nie będą działać dobrze, gdy stan zostanie zapisany / przywrócony, ponieważFragmentStatePagerAdapter
może nie wywoływać wywołań zwrotnych po przywróceniu stanu.Jedyną rzeczą, którą udało mi się wykonać, jest skopiowanie kodu
FragmentStatePagerAdapter
i dodanie metody, która zwraca fragment, biorąc pod uwagę pozycję (mFragments.get(pos)
). Zauważ, że ta metoda zakłada, że fragment jest faktycznie dostępny (tj. Był widoczny w pewnym momencie).Jeśli jesteś szczególnie żądny przygód, możesz użyć refleksji, aby uzyskać dostęp do elementów prywatnej
mFragments
listy, ale wrócimy do pierwszego punktu (nazwa listy nie jest taka sama).źródło
Prześlij instancję odzyskaną z powyższej linii do fragmentu, nad którym chcesz pracować. Działa idealnie dobrze.
to instancja pager zarządzająca fragmentami.
źródło
Aby uzyskać odniesienie do aktualnie widocznego fragmentu, załóż, że masz odniesienie do
ViewPager
asmPager
. Następnie następujące kroki otrzymają odniesienie docurrentFragment
:PageAdapter adapter = mPager.getAdapter();
int fragmentIndex = mPager.getCurrentItem();
FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
Fragment currentFragment = fspa.getItem(fragmentIndex);
Jedynie użyta obsada 3 linii jest zwykle ważna.
FragmentStatePagerAdapter
jest przydatnym adapterem do ViewPager.źródło
Najlepszym sposobem na to, po prostu wywołaj fragment CallingFragmentName = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Ponownie utworzy instancję twojego fragmentu wywołującego, aby nie zgłaszał wyjątku zerowego wskaźnika i nie wywoła żadnej metody tego fragmentu.
źródło
Aktualny fragment:
Działa to, jeśli utworzyłeś projekt z szablonem paska zakładek fragmentów.
Zauważ, że działa to z domyślną implementacją szablonu działania z zakładkami.
źródło
Użyłem następujących:
źródło
FragmentStatePagerAdapter
ma zmienną instancji prywatnej o nazwiemCurrentPrimaryItem
typeFragment
. Można się tylko zastanawiać, dlaczego deweloperzy Androida nie dostarczyli go z getterem. Ta zmienna jest tworzona wsetPrimaryItem()
metodzie. Zastąp więc tę metodę, aby uzyskać odniesienie do tej zmiennej. Po prostu skończyłem z zadeklarowaniem własnegomCurrentPrimaryItem
i skopiowaniem treścisetPrimaryItem()
do mojego zastąpienia.W swojej realizacji
FragmentStatePagerAdapter
:źródło
Można zdefiniować
PagerAdapter
jak to wtedy będzie w stanie uzyskać żadnejFragment
inViewPager
.Aby uzyskać prąd
Fragment
źródło
Gdy korzystamy z viewPager, dobrym sposobem na uzyskanie dostępu do instancji fragmentu w działaniu jest instantiateItem (viewpager, indeks). // indeks - indeks fragmentu, którego chcesz instancji.
na przykład uzyskuję dostęp do instancji fragmentu 1 indeksu
źródło
Miałem ten sam problem i rozwiązałem go za pomocą tego kodu.
Wystarczy zastąpić nazwę MyFragment nazwą swojego fragmentu i dodać identyfikator kontenera fragmentów.
źródło
Jest to bardziej przyszłościowe niż przyjęta odpowiedź:
źródło
Omawiany scenariusz jest lepiej obsługiwany przez każdy Fragment dodający własne pozycje menu i bezpośrednio obsługujący onOptionsItemSelected (), jak opisano w oficjalnej dokumentacji . Lepiej unikać nieudokumentowanych sztuczek.
źródło
ViewPager
problem?Po przeczytaniu wszystkich komentarzy i odpowiedzi wyjaśnię optymalne rozwiązanie tego problemu. Najlepszą opcją jest rozwiązanie @ rik, więc moja poprawa jest oparta na jego.
Zamiast pytać o to jak każdy FragmentClass
Utwórz własny interfejs i spraw, aby fragmenty dziecka zaimplementowały go, coś w rodzaju
Następnie możesz zrobić coś takiego, aby zainicjować i zaktualizować swoje wewnętrzne fragmenty.
PS Zachowaj ostrożność, gdy umieścisz ten kod, jeśli wywołasz insatiateItem przed faktycznym utworzeniem go przez system,
savedInstanceState
fragment Twojego dziecka będzie pustyAwaria Twojej aplikacji.
Powodzenia
źródło
W oparciu o to, na co odpowiedział @chahat jain:
„Gdy korzystamy z viewPager, dobrym sposobem na uzyskanie dostępu do instancji fragmentu w działaniu jest instantiateItem (viewpager, indeks). // indeks-indeks fragmentu, którego chcesz instancję.”
Jeśli chcesz to zrobić w Kotlin
0 do fragmentu fragmentu 0
// ================================================ ========================= // // ##################### ######## Przykład zastosowania ############################################### // // == ================================================== ===================== //
Oto kompletny przykład najsłabszej wizji
oto mój veiewPager w pliku .xml
I aktywność domowa, w której wstawiam kartę
źródło
W mojej poprzedniej implementacji zapisałem listę Fragmentów potomnych, aby mieć do nich dostęp później, ale okazało się, że była to niewłaściwa implementacja powodująca ogromne wycieki pamięci.
W końcu używam
instantiateItem(...)
metody, aby uzyskać aktualny fragment:Lub uzyskać inny Fragment na pozycji:
Z dokumentacji :
źródło
W mojej działalności mam:
źródło
Czasami fragment może wywołać pusty obiekt, więc można uruchomić nowy plik Runnable, aby rozwiązać problem przy pierwszym ładowaniu.
Dziękuję Rick
źródło
Przesłoń setPrimaryItem z Twojego FragmentPagerAdapter: obiekt jest widocznym fragmentem:
źródło
Wystarczy pobrać bieżący element z pagera, a następnie poprosić adapter o fragment tej pozycji.
źródło
getItem
utworzy nową instancjęAby uzyskać bieżący fragment - uzyskaj pozycję w ViewPager w public void onPageSelected (końcowa pozycja int) , a następnie
SECTNUM - argument pozycji przypisany publicznie statyczny PlaceholderFragment newInstance (int sectionNumber); fragmentu
getChildFragmentManager () lub getFragmentManager () - zależy od tego, jak utworzono SectionsPagerAdapter
źródło
Możesz zaimplementować BroadcastReceiver we fragmencie i wysłać zamiar z dowolnego miejsca. Odbiornik fragmentu może nasłuchiwać określonej akcji i wywoływać metodę instancji.
Jednym zastrzeżeniem jest upewnienie się, że komponent View jest już utworzony i (a dla niektórych operacji, takich jak przewijanie listy, ListView musi być już zrenderowany).
źródło
To najprostszy hack:
(kod kotlin)
Wystarczy zadzwonić
instantiateItem(viewPager, viewPager.getCurrentItem()
i przesłać naFragment
. Twój przedmiot zostałby już utworzony. Dla pewności możesz dodać czek dlagetCount
.Działa zarówno z, jak
FragmentPagerAdapter
iFragmentStatePagerAdapter
!źródło
Jeśli twój pager znajduje się we fragmencie, użyj tego:
Gdzie
R.id.myViewPagerId
jest identyfikator twojego ViewPager w układzie xml.źródło
Możesz zadeklarować tablicę fragmentów jako fragmenty rejestru
Następnie możesz użyć go jako
źródło