Recupera un frammento da un ViewPager


248

Sto usando un ViewPagerinsieme a un FragmentStatePagerAdapterper ospitare tre diversi frammenti:

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

Quando voglio ottenere Fragment1dal ViewPagerin FragmentActivity.

Qual è il problema e come posso risolverlo?

Risposte:


504

La risposta principale si basa su un nome generato dal framework. Se questo dovesse mai cambiare, allora non funzionerà più.

Che dire di questa soluzione, di priorità instantiateItem()e destroyItem()del tuo 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);
    }
}

Questo sembra funzionare per me quando ho a che fare con frammenti disponibili. I frammenti che non sono stati ancora istanziati, restituiranno null quando si chiama getRegisteredFragment. Ma lo sto usando principalmente per Fragmentestrarre la corrente da ViewPager: adapater.getRegisteredFragment(viewPager.getCurrentItem())e questo non ritornerà null.

Non sono a conoscenza di altri svantaggi di questa soluzione. Se ce ne sono, mi piacerebbe saperlo.


41
Questa è la soluzione migliore a cui riesco a pensare. L'unico suggerimento potrebbe essere quello di avvolgere il file Fragmentin a WeakReferenceper garantire di non impedire che un frammento distrutto venga raccolto? Sembra proprio la cosa giusta da fare ...
Alex Lockwood,

7
Cosa succede quando MyPagerAdapterviene distrutto a causa del ciclo di vita (cioè ruota), non registerdFragmentsandrà perso? Il Activity/ Fragmentusing MyPagerAdapterdovrà salvarlo in onSaveInstanceState, e quindi dovrà aggiornarlo con il nuovo riferimento FragmentManager?
Steven Byle,

10
Se non sbaglio (e dovresti verificarlo), il metodo getItem non viene chiamato - come sai - ma il metodo instantiateItem viene chiamato per ogni frammento che viene ripristinato dal framework dopo una rotazione.
Streets Of Boston,

6
Sì, ho verificato che getItemnon viene più richiamato su rotate (per eventuali frags che sono già stati creati), poiché FragmentManagerripristina gli stati di Fragmentsesso contenuti nel cercapersone. Se instantiateItemviene chiamato quando ciascuno Fragmentviene ripristinato, questa soluzione è in realtà più sicura e più a prova di futuro della mia o della risposta accettata. Prenderò in considerazione di provare questo da solo.
Steven Byle,

6
@Dori Non lo rompo. La mia soluzione non sta usando il risultato della chiamata 'getItem ()'. Invece, utilizza il risultato memorizzato dalla chiamata 'instantiateItem ()'. E il ciclo di vita del frammento non viene interrotto, poiché il frammento memorizzato verrà rimosso dall'array sparse sulla chiamata 'destroyItem ()'.
Streets Of Boston,

85

Per estrarre frammenti da un ViewPager ci sono molte risposte qui e su altri thread / blog SO correlati. Tutti quelli che ho visto sono rotti e generalmente sembrano rientrare in uno dei due tipi elencati di seguito. Ci sono alcune altre soluzioni valide se vuoi solo afferrare il frammento corrente, come questa altra risposta su questo thread.

Se si utilizza FragmentPagerAdaptervedere di seguito. Se ne FragmentStatePagerAdaptervale la pena guardare questo . Afferrare gli indici che non sono quelli attuali in un FragmentStateAdapter non è così utile in quanto per loro natura questi saranno completamente abbattuti, fuori dalla vista / fuori dai limiti offScreenLimit.

I SENTIERI FELICI

Sbagliato: mantenere il proprio elenco interno di frammenti, aggiunto a quando FragmentPagerAdapter.getItem()viene chiamato

  • Di solito usando un SparseArrayoMap
  • Nessuno dei tanti esempi che ho visto rappresenta gli eventi del ciclo di vita, quindi questa soluzione è fragile. Come getItemviene chiamato solo la prima volta che una pagina viene spostata (o ottenuta se ViewPager.setOffscreenPageLimit(x)> 0) in ViewPager, se l'hosting Activity/ Fragmentviene ucciso o riavviato, l'interno SpaseArrayverrà cancellato quando viene ricreata la FragmentPagerActivity personalizzata, ma dietro le quinte il ViewPagers frammenti interni saranno ricreati, e getItemsaranno non essere chiamati per qualsiasi degli indici, così la possibilità di ottenere un frammento di indice verranno persi per sempre. Puoi renderlo conto salvando e ripristinando questi riferimenti a frammenti tramite FragmentManager.getFragment()e putFragmentma questo inizia a diventare IMHO disordinato.

Sbagliato: costruisci il tuo tag id corrispondente a quello che viene usato sotto il cofanoFragmentPagerAdapter e usalo per recuperare i frammenti di pagina dalFragmentManager

  • Questo è meglio in quanto affronta il problema dei riferimenti a frammenti perdenti nella prima soluzione di array interno, ma come giustamente sottolineato nelle risposte sopra e altrove sulla rete - sembra confuso perché è un metodo privato interno a ViewPagerquello che potrebbe cambiare in qualsiasi momento o per qualsiasi versione del sistema operativo.

Il metodo ricreato per questa soluzione è

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

UN PERCORSO FELICE: ViewPager.instantiateItem()

Un approccio simile a quello getItem()sopra, ma non interruzione del ciclo di vita, è quello di agganciare instantiateItem()invece di getItem()come il primo verrà chiamato ogni volta che l'indice viene creato / accessibile. Vedi questa risposta

UN PERCORSO FELICE: costruisci il tuo FragmentViewPager

Costruisci la tua FragmentViewPagerclasse dall'origine della più recente libreria di supporto e modifica il metodo utilizzato internamente per generare i tag di frammento. Puoi sostituirlo con il seguente. Questo ha il vantaggio di sapere che la creazione del tag non cambierà mai e di non fare affidamento su un metodo / API privato, che è sempre pericoloso.

/**
 * @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;
}

Quindi, come dice il documento, quando si desidera afferrare un frammento utilizzato per un indice, chiamare semplicemente qualcosa come questo metodo (che è possibile inserire nella FragmentPagerAdaptersottoclasse personalizzata o)) tenendo presente che il risultato potrebbe essere nullo se getItem non è stato ancora richiesto quella pagina cioè non è stata ancora creata.

/**
 * @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;
}

Questa è una soluzione semplice e risolve i problemi nelle altre due soluzioni presenti ovunque sul Web


6
Funzionerà, ma richiede la copia della classe ViewPager nel tuo codice sorgente. Affidarsi a 'instantiateItem ()' e 'destroyItem ()' dell'adattatore per cercapersone di ViewPager funzionerà e rispetterà i cicli di vita dei frammenti (questi 2 metodi vengono chiamati anche quando i frammenti vengono creati da uno stato di istanza salvato). Hai ragione, fare affidamento sul fatto che 'getItem ()' venga chiamato non è una buona idea e l'utilizzo di API private non lo è.
Streets Of Boston,

+1 sono d'accordo che è anche una soluzione e ho modificato sopra. L'unica differenza è che quanto sopra funziona in un altro caso d'uso quello instantiateItem()che è quando si desidera accedere a un frammento che non è stato ancora visitato dopo che si è verificato un evento del ciclo di vita e che è stato visitato prima dell'evento del ciclo di vita. Una piccola differenza che conosco, ma è quella che ha portato a un bug sottile nel mio programma, quindi mi sto guardando in questo.
Dori,

Se setOffscreenPageLimit = 1 (impostazione predefinita), FragmentStatePageAdapter inizierà a scambiare i frammenti all'interno e all'esterno della memoria quando si accede alle pagine di visualizzazione. Con una chiamata a getItem () verrà quindi creata una nuova istanza di pagine / frammenti rivisitati. Su tale revisione, c'è un modo per istruire il sistema a riprendere istanze create in precedenza, piuttosto che crearne una nuova?
Carl

se al di fuori del limite della pagina dovrà crearne uno nuovo, ma passando nello stato salvato. Se vuoi mantenere in giro quelli vecchi, potresti aumentare il limite della pagina
Dori,

@Dori non c'è getItemId(pos)dentroFragmentStatePagerAdapter
Jemshit Iskenderov il

70

Aggiungi i seguenti metodi al tuo 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) deve funzionare.

Ecco la soluzione implementata in ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Se qualcosa fallisce vedrai un buon registro degli arresti anomali.


Molte grazie:) . Attraverso l'ho sostituito in un altro modo in cui uso un gestore per pubblicare il frammento. Questo non è molto adatto ma alla fine ha risolto il problema. A proposito, sei gentile :)
Qun Qin

12
Stavo usando questo metodo, ma credo che abbia smesso di funzionare quando sono passato all'API 17 (?). Consiglierei un altro metodo e lo preferirei se Google pubblicasse semplicemente un'API per recuperare un frammento da un ViewPager, data la sua posizione.
gcl1,

ho un problema con la chiamata del secondo frammento, il metodo creane uno nuovo
Vasil Valchev

2
Poiché alcune versioni dell'API del metodo makeFragmentName sono state modificate in String private stat makeFragmentName (int viewId, long id) {return "android: switcher:" + viewId + ":" + id; } quindi il metodo getActiveFragment ora dovrebbe assomigliare a questo (usare getItemId invece della posizione per il secondo argomento) Frammento pubblico getActiveFragment (contenitore ViewPager, int position) {Nome stringa = makeFragmentName (container.getId (), getItemId (position)); return mFragmentManager.findFragmentByTag (nome); }
Eugene Popovich,

1
Funziona davvero, ma è davvero pericoloso perché si ripercuote sull'implementazione interna del cercapersone di visualizzazione e se Google cambierà l'implementazione (e possono) succederanno cose brutte. Spero davvero che Goole lo renda disponibile per ottenere il frammento dal vivo
Trans

38

Un'altra soluzione semplice:

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

1
Questo sembra perfetto per le mie attuali esigenze di frammento.
danny117,

Se tutto ciò che devi fare è ottenere il frammento attualmente selezionato, questo è tutto ciò di cui hai bisogno: il metodo setPrimaryItem è impostato su attach e anche su ogni aggiornamento del set interno del frammento come elemento corrente.
Graeme,

1
Sembra una buona soluzione, ma come setPrimaryItem()viene chiamato dopo ViewPager.OnPageChangeListener#onPageSelected() non posso usarlo :-(
hardysim

21

So che questo ha alcune risposte, ma forse questo aiuterà qualcuno. Ho usato una soluzione relativamente semplice quando avevo bisogno di ottenere un Fragmentmio ViewPager. Nel tuo Activityo Fragmenttenendo premuto il ViewPager, puoi usare questo codice per scorrere tutto Fragmentciò che contiene.

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.
    }
}
  • Se conosci la tua posizione Fragmentin ViewPager, puoi semplicemente chiamare getItem(knownPosition).

  • Se non conosci la posizione del tuo Fragmentin ViewPager, puoi avere i tuoi figli Fragmentsimplementare un'interfaccia con un metodo simile getUniqueId()e usarlo per differenziarli. Oppure puoi scorrere tutto Fragmentse controllare il tipo di classe, ad esempioif(viewPagerFragment instanceof FragmentClassYouWant)

!!! MODIFICARE !!!

Ho scoperto che getItemviene chiamato da un solo FragmentPagerAdapterquando ognuno Fragmentdeve essere creato la prima volta , dopodiché, sembra che Fragmentsvengano riciclati usando il FragmentManager. In questo modo, molte implementazioni diFragmentPagerAdapter creare nuove Fragment s in getItem. Usando il mio metodo sopra, questo significa che creeremo nuove Fragments ogni volta che getItemviene chiamato mentre esaminiamo tutti gli elementi in FragmentPagerAdapter. A causa di ciò, ho trovato un approccio migliore, usando invece FragmentManagerper ottenere ciascuno Fragment(usando la risposta accettata). Questa è una soluzione più completa e ha funzionato bene per me.

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

E avrai bisogno di questo metodo.

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

1
Hai appena trovatoFragmentByTag (), ma dove potremmo impostare il TAG con frammento ??
VinceStyling

@vince Lo ViewPagerstesso imposta quei tag. Questa soluzione è fragile perché si basa sulla conoscenza della convenzione di denominazione "nascosta" di ViewPager. La risposta di Streets of Boston è una soluzione molto più completa, che ora uso nel mio progetto (anziché in questo approccio).
Steven Byle,

Funziona benissimo! Ma ho rimosso il condizionale "if (viewPagerFragment.isResumed ())" perché devo aggiornare le mie pagine ListFragment che sono fuori schermo. Quindi, quando l'utente torna alla pagina ListFragment, viene tutto aggiornato con i nuovi dati.
JDJ,

10

Nel mio caso, nessuna delle soluzioni di cui sopra ha funzionato.

Tuttavia, poiché sto utilizzando Child Fragment Manager in un frammento, è stato utilizzato quanto segue:

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

Funzionerà solo se i tuoi frammenti in Manager corrispondono all'elemento viewpager.


Questa è la risposta perfetta per ottenere vecchi frammenti dal pager della vista quando viene ricreata l'attività o il frammento.
Smeet,

7

Per ottenere l' attuale frammento visibile da ViewPager . Sto usando questa semplice affermazione e funziona benissimo.

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }

3

L'ho gestito facendo prima un elenco di tutti i frammenti ( List<Fragment> fragments;) che stavo per usare, quindi li ho aggiunti al cercapersone per semplificare la gestione del frammento attualmente visualizzato.

Così:

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

quindi questo può essere chiamato:

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

così ho potuto scriverlo in un'istruzione if che sarebbe stata eseguita solo se fosse sul frammento corretto

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

ma questo è solo il mio approccio di hack e slash ma ha funzionato per me, lo uso faccio modifiche rilevanti al mio frammento attualmente visualizzato quando viene premuto il pulsante Indietro.


1
migliore risposta per me
Sonu Kumar

3

Questo si basa sulla risposta di Steven sopra. Ciò restituirà l'istanza effettiva del frammento che è già associato all'attività padre.

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

2

Non sono riuscito a trovare un modo semplice e pulito per farlo. Tuttavia, il widget ViewPager è solo un altro ViewGroup, che ospita i tuoi frammenti. ViewPager ha questi frammenti come figli immediati. Quindi potresti semplicemente scorrere su di essi (usando .getChildCount () e .getChildAt ()), e vedere se l'istanza di frammento che stai cercando è attualmente caricata nel ViewPager e ottenere un riferimento ad esso. Ad esempio, è possibile utilizzare un campo ID univoco statico per distinguere i frammenti.

Nota che ViewPager potrebbe non aver caricato il frammento che stai cercando poiché è un contenitore di virtualizzazione come ListView.


1
Grazie per la tua risposta, l'ho recuperato con l'adpter.getItem (); Sono una matricola nella programmazione Android. ti apprezzo davvero tanto. Ora posso recuperare ListFragment e voglio aggiungere footerView ad esso, mentre lo faccio nella mia attività, il logcat stampa: "java.lang.IllegalStateException: vista contenuto non ancora creata." So perché ma ho difficoltà a gestire con esso.
Qun Qin

1
FragmentActivity ha il metodo onAttachFragment (), dosare questo lavoro per ViewPager con contenuto di frammenti?
Vasil Valchev

2

FragmentPagerAdapter è la fabbrica dei frammenti. Per trovare un frammento basato sulla sua posizione se è ancora in memoria, usa questo:

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

Codice di esempio per API di supporto v4.


Restituisce null in onresume (). Hai idea del perché e della zappa per ripararlo?
seema

2

Non è necessario chiamare getItem()o altri metodi in una fase successiva per ottenere il riferimento di un Fragmenthost ospitato all'interno ViewPager. Se desideri aggiornare alcuni dati all'interno, Fragmentutilizza questo approccio: Aggiorna ViewPager in modo dinamico?

La chiave è quella di impostare nuovi dati all'interno Adapere chiamare quelli notifyDataSetChanged()che a loro volta chiameranno getItemPosition(), passandoti un tuo riferimento Fragmente dandoti la possibilità di aggiornarli. Tutti gli altri modi richiedono di fare riferimento a te stesso o ad altri hack che non sono una buona soluzione.

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

Non capisco qui, hai bisogno di un riferimento di un frammento per usare getItemPosition (), quindi potresti non usare getItemPosition, eh?

getItemPosition()è un metodo nel tuo adattatore. Non lo chiamerai direttamente. Hai un riferimento del tuo adattatore, così chiami adapter.notifyDataSetChanged()chi a sua volta chiamerà il getItemPosition()tuo adattatore passando il riferimento dei tuoi Fragment. Potete vedere una piena attuazione in azione qui stackoverflow.com/questions/19891828/...
M-Wajeeh

L'ho letto e ancora non capisco. Avresti ancora bisogno di un riferimento diretto a quei frammenti per effettuare chiamate contro di loro, giusto? Lo dici come un trucco ma non vedo un'alternativa; adapter.getItem (i) ovviamente non funzionerà.

2
Ok ho aggiornato la mia risposta per chiarire di più. Naturalmente è necessario un riferimento per aggiornare un, Fragmentma come ottenere un riferimento è discutibile. Altre soluzioni ottengono riferimenti FragmentManagerdall'uso di una stringa simile "android:switcher:"+ido POSITION_NONEdalla restituzione getItemosition()causando la rigenerazione di tutti i frammenti.
M-WaJeEh,

Grazie, questo ha molto più senso e corrisponde alla mia esperienza (quindi potrei non fare qualcosa di sbagliato, ah).

2

Deve estendersi FragmentPagerAdapteralla classe dell'adattatore ViewPager.
Se si utilizza FragmentStatePagerAdapterallora non si sarà in grado di trovare il vostro Fragmentdal suoID

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

Come usare questo metodo: -

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;

2

Ehi, ho risposto a questa domanda qui . Fondamentalmente, è necessario eseguire l'override

public Object instantiateItem (contenitore ViewGroup, posizione int)

metodo di FragmentStatePagerAdapter.


1

La soluzione migliore è utilizzare l'estensione che abbiamo creato in CodePath chiamato SmartFragmentStatePagerAdapter . Seguendo tale guida, ciò semplifica notevolmente il recupero di frammenti e il frammento attualmente selezionato da un ViewPager. Fa anche un lavoro migliore nella gestione della memoria dei frammenti incorporati nell'adattatore.


0

Il modo più semplice e più conciso. Se tutti i tuoi frammenti ViewPagersono di classi diverse, puoi recuperarli e distinguerli come segue:

public class MyActivity extends Activity
{

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

}

Anche questo è sbagliato, poiché ci sono più frammenti che vengono collegati quando si utilizza ViewPager. c'è il frammento di pagina corrente e ce n'è uno alla sua sinistra e uno alla sua destra. Ciò consente all'utente di scorrere tra di loro senza dover inizializzarli solo quando l'utente li raggiunge.
sviluppatore Android il

0

Ho implementato questo facilmente con un approccio un po 'diverso.

Il mio metodo FragmentAdapter.getItem personalizzato non ha restituito MyFragment (), ma l'istanza di MyFragment creata nel costruttore di FragmentAdapter.

Nella mia attività ho quindi ottenuto il frammento dall'adattatore, verificare se si tratta dell'istanza di frammento necessario, quindi eseguire il cast e utilizzare i metodi necessari.


0

Crea un ID risorsa intero in /values/integers.xml

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

Quindi nella funzione getItem di 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;
        }

Quindi nell'attività scrivi questa funzione per ottenere il riferimento al frammento:

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

Ottieni il riferimento al frammento chiamando la funzione sopra e quindi esegui il cast sul frammento personalizzato:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }

0

Modo semplice per scorrere i frammenti in Gestione frammenti. Trova viewpager, che ha l'argomento position position, inserito in PlaceholderFragment newInstance statico pubblico (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;
}

0

Nel frammento

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

}

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

0

in TabLayout ci sono più schede per Frammento. puoi trovare il frammento per Tag usando l'indice del frammento.

Per es. l'indice per Fragment1 è 0, quindi nel findFragmentByTag()metodo passa il tag per Viewpager.after usando fragmentTransaction che puoi aggiungere, sostituisci il frammento.

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


-1

Ok per l'adattatore FragmentStatePagerAdapter ho finanziato una soluzione:

nel tuo frammentoAttività:

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

e crea un metodo nella tua classe FragmentActivity - Quindi quel metodo ti dà accesso al tuo frammento, devi solo dargli la posizione del frammento che desideri:

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

nel tuo adattatore:

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

}

-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

indexè il posto del frammento nell'adattatore come hai aggiunto fragment1prima, quindi riprendi il fragment1passaggio indexcome 0 e così via per il resto

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.