Obtention de l'instance de fragment actuelle dans le visualiseur

210

Ci-dessous est mon code qui a 3 Fragment classeschacun intégré avec chacun des 3 onglets ViewPager. J'ai une option de menu. Comme indiqué dans le onOptionsItemSelected(), en sélectionnant une option, je dois mettre à jour le fragment actuellement visible. Pour mettre à jour cela, je dois appeler une méthode qui est dans la classe des fragments. Quelqu'un peut-il suggérer comment appeler cette méthode?

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

     }

    }

Supposons que ci-dessous soit la classe de fragment avec la méthode que updateList()je veux appeler:

 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
    }
}
meule
la source
quelle méthode de fragment voulez-vous appeler?
Biraj Zalavadia
@BirajZalavadia Ma propre méthode définie, qui contient un paramètre et utilise les variables d'instance de cette classe de fragments qui ont déjà été initialisées lors de la création d'une vue même.
rick
1
pouvez-vous donner le nom de classe de vos fragments qui sont dans le viseur?
Biraj Zalavadia
Le moyen le plus simple d'accéder aux fragments visibles serait via stackoverflow.com/questions/7379165/… , regardez les deux premières réponses.
Luksprog

Réponses:

205

en sélectionnant une option, j'ai besoin de mettre à jour le fragment qui est actuellement visible.

Une façon simple de le faire consiste à utiliser une astuce liée à la FragmentPagerAdaptermise en œuvre:

case R.id.addText:
     Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
     // based on the current position you can then cast the page to the correct 
     // class and call the method:
     if (ViewPager.getCurrentItem() == 0 && page != null) {
          ((FragmentClass1)page).updateList("new item");     
     } 
return true;

Veuillez repenser votre convention de dénomination des variables, en utilisant comme nom de variable le nom de la classe est très déroutant (donc non ViewPager ViewPager, utilisez ViewPager mPagerpar exemple).

Luksprog
la source
23
Cette balise de fragment est-elle à l'épreuve du temps, si l'API change?
Maarten
7
@Maarten Non, c'est juste un hack commun qui a été utilisé depuis que l'adaptateur est apparu (et son code source était disponible), il n'a pas encore changé. Si vous voulez quelque chose de plus fiable, vous devrez utiliser d'autres options, notamment en remplaçant la instantiateItem()méthode et en obtenant vous-même les références aux fragments appropriés.
Luksprog
5
Après des heures de frustration et de demander les pages directement de la mAdapter.getItem(position), génial ... Au moins maintenant, je sais que les autres essais 8512 n'ont pas fonctionné. Merci
Diolor
29
Notez que cela ne fonctionne pas si vous utilisez FragmentStatePagerAdapter plutôt que FragmentPagerAdapter.
Shawn Lauzon
3
@ShawnLauzon FragmentStatePagerAdapter a une implémentation différente, dans son cas, vous appelez sa méthode instantiateItem () pour obtenir les fragments visibles.
Luksprog
155
    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
la source
29
Google doit fournir FragmentPageAdapter.getCurrentPrimaryItem () renvoyant mCurrentPrimaryItem.
eugene
1
J'utilise également cette technique, je définis également un PagerFragment avec des méthodes onPageSelected/ onPageDeselectedet je fais en sorte que tous mes fragments de pager le prolongent. Vous setPrimaryitempouvez ensuite appeler ces méthodes de manière appropriée lorsque l'utilisateur glisse vers une nouvelle page. Cela signifie que vous pouvez implémenter une stratégie plus paresseuse pour le chargement de données dans des pages qui ne sont même pas affichées. Cependant, vous devez garder à l'esprit que pendant la transition de page, il est préférable que la page suivante soit déjà remplie de données, donc le chargement paresseux de toutes les données dans onPageSelectedpeut ne pas être idéal.
JHH
3
Pourquoi la ifdéclaration? Le fragment appelle simplement la equalsméthode de l'objet, qui est une comparaison superficielle. Alors pourquoi ne pas toujours appeler mCurrentFragment = ((Fragment) object);?
Overclover
essayé et cela fonctionne bien, il suffit de lancer le getCurrentFragment () sur le fragment spécifique qu'il devrait
PhilipJ
113

Tout d'abord, gardez une trace de toutes les pages de fragments "actifs". Dans ce cas, vous gardez une trace des pages de fragments dans FragmentStatePagerAdapter, qui est utilisé par ViewPager.

@Override
public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

Pour éviter de conserver une référence aux pages de fragments "inactifs", vous devez implémenter la méthode destroyItem (...) de FragmentStatePagerAdapter:

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

et lorsque vous devez accéder à la page actuellement visible, vous appelez alors:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

Où la méthode getFragment (int) de MyAdapter ressemble à ceci:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

J'espère que cela peut aider!

FraZer
la source
Pouvez-vous expliquer clairement? Où dois-je conserver cette classe FragmentStatePagerAdapter dans mon code? BTW J'ai 3 classes de fragments, pas une seule MyFragmentClass.
rick
7
Encore mieux si vous mettez à jour mPageReferenceMap dans instantiateItem au lieu de getItem car cela fonctionne également après un changement d'orientation. '@Override public Object instantiateItem (conteneur ViewGroup, position int) {Fragment fragment = (Fragment) Super.instantiateItem (conteneur, position); mPageReferenceMap.put (position, fragment); fragment de retour; } '
pmellaaho
De quel type est mPageReferenceMap?
DoruAdryan
10
Cette réponse est vraiment mauvaise! Vous ne devez pas conserver le cache d'un ViewPager manuellement car il le gère seul. Le ViewPager décide quand le fragment doit être alloué ou non, quoi suspendre et quand, garder une référence sur chaque fragment ajoutera une surcharge inutile et n'est pas optimisé pour la mémoire.
Livio
3
J'ai essayé cette approche mais malheureusement ça ne marche pas quand l'activité est recréée. Sur Android N et versions ultérieures, vous pouvez le voir lorsque vous utilisez la fonctionnalité de fenêtres multiples. Lorsque votre application est ouverte, maintenez longuement le bouton `` Récents '' (le carré). L'activité et le fragment sont recréés à partir de savedInstanceState, l'adaptateur est recréé (donc mPageReferenceMap est maintenant vide), mais getItem n'est pas appelé à nouveau. La carte reste vide, donc adapter.getFragment (index) va planter.
Martin Konicek
102

C'est la seule façon dont je n'obtiens pas NullPointerException pour les variables d'instance de ces classes de fragments particulières. Cela pourrait être utile pour d'autres qui s'en tiennent à la même chose. Dans onOptionsItemSelected (), j'ai codé comme suit:

if(viewPager.getCurrentItem() == 0) {
    FragmentClass1 frag1 = (FragmentClass1)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag1.updateList(text); 
} else if(viewPager.getCurrentItem() == 1) {
    FragmentClass2 frag2 = (FragRecentApps)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag2.updateList(text);
}
meule
la source
3
Je pense que c'est la réponse la plus correcte - aligner avec la conception de FragmentStatePagerAdaptersans remplacer aucun code. En fait, cela devrait être aussi simple qu'une fonction de retour viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
John Pang
39

FragmentStatePagerAdapter a une méthode publique avec le nom instantiateItem qui renvoie votre fragment en fonction des valeurs de paramètre spécifiées, cette méthode a deux paramètres ViewGroup (ViewPager) et position.

public Object instantiateItem(ViewGroup container, int position);

Utilisé cette méthode pour obtenir le fragment de position spécifié,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);
Krunal Shah
la source
5
Mais cela ne renvoie pas le fragment déjà instancié actuel, mais un nouveau à la place, non? Ainsi nom "instancier" ...
Ixx
1
@Ixx Non, il ne crée pas de nouveau fragment. Je pense que le nom de la méthode est incorrect ici.
Bugs Happen
15

Je sais que c'est trop tard mais j'ai des moyens très simples de le faire,

// pour fragment à 0 possession

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();
Pratik Mhatre
la source
10

Il y a beaucoup de réponses ici qui ne répondent pas vraiment au fait fondamental qu'il n'y a vraiment AUCUNE FAÇON de le faire de manière prévisible, et d'une manière qui ne vous empêche pas de vous tirer une balle dans le pied à un moment donné dans le futur.

FragmentStatePagerAdapterest la seule classe qui sait accéder de manière fiable aux fragments qui sont suivis par le FragmentManager- toute tentative pour essayer de deviner l'identifiant ou la balise du fragment n'est pas fiable à long terme. Et les tentatives de suivi manuel des instances ne fonctionneront probablement pas bien lorsque l'état est enregistré / restauré, carFragmentStatePagerAdapter peut bien que les rappels ne soient pas rappelés lors de la restauration de l'état.

À propos de la seule chose que j'ai pu faire fonctionner, c'est la copie du code FragmentStatePagerAdapteret l'ajout d'une méthode qui renvoie le fragment, étant donné une position ( mFragments.get(pos)). Notez que cette méthode suppose que le fragment est réellement disponible (c'est-à-dire qu'il était visible à un moment donné).

Si vous êtes particulièrement aventureux, vous pouvez utiliser la réflexion pour accéder aux éléments de la mFragmentsliste privée , mais nous revenons à la case départ (le nom de la liste n'est pas garanti de rester le même).

Melllvar
la source
1
pour gérer le "ne fonctionne pas bien lorsque l'état est enregistré / restauré", je remplace la méthode saveState (). Pour que le pager n'enregistre aucun fragment lorsque l'activité est suspendue. Ça marche.
AntoineP
2
Cela ne fait qu'ajouter au patchwork, sans résoudre le problème sous-jacent. Je ne dis pas que cela ne fonctionne pas - juste que ce n'est pas une bonne mise en œuvre.
Melllvar
8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Convertissez l'instance récupérée de la ligne ci-dessus dans le fragment sur lequel vous souhaitez travailler. Fonctionne parfaitement bien.

viewPager

est l'instance de pager gérant les fragments.

Gaurav Pangam
la source
Cela ne fonctionne que si toutes les pages sont chargées en tant que fragment. Lorsqu'il y a par exemple un tablayout avec de nombreux onglets / pages, alors tous ne sont pas chargés, ce qui pourrait déclencher une exception indexoutofbounce.
progNewbie
@progNewbie oui qui aura besoin d'un code de contournement supplémentaire.
Gaurav Pangam
La réponse de @progNewbie Evgeny ci-dessous gérerait cette situation je pense
Gaurav Pangam
7

en sélectionnant une option, j'ai besoin de mettre à jour le fragment qui est actuellement visible.

Pour obtenir une référence au fragment actuellement visible, supposez que vous avez une référence à ViewPageras mPager. Ensuite, les étapes suivantes obtiendront une référence à currentFragment:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

La seule ligne de distribution utilisée 3 est généralement valide. FragmentStatePagerAdapterest un adaptateur utile pour un ViewPager.

user4665465
la source
7

La meilleure façon de le faire, appelez simplement CallingFragmentName fragment = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Il réinstanciera votre fragment appelant, de sorte qu'il ne lèvera pas d'exception de pointeur nul et n'appellera aucune méthode de ce fragment.

Ritesh Adulkar
la source
6

Fragment actuel:

Cela fonctionne si vous avez créé un projet avec le modèle de barre d'onglets de fragments.

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

Notez que cela fonctionne avec l'implémentation du modèle d'activité à onglets par défaut.

hasan
la source
30
Cela dépend de votre implémentation de getItem () - il peut retourner une nouvelle instance du fragment, ce qui n'est probablement pas ce que vous voulez.
Tom
C'est comme ça que tu le fais. si vous avez toujours la configuration par défaut lorsque vous créez un projet tabor with fragments. aucun n'avait cette solution. alors j'ai pensé que ça aiderait.
hasan
3

J'ai utilisé ce qui suit:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);
réel 19
la source
1
Cela repose sur une implémentation de pager personnalisée à partir de la réponse trouvée ici: stackoverflow.com/questions/8785221/…
Tom Redman
1
C'est exactement ce que j'essayais de faire, mais sans savoir quelles méthodes remplacer, j'aurais perdu des heures - merci!
Bron Davies
2

FragmentStatePagerAdaptera une variable d'instance privée appelée mCurrentPrimaryItemde type Fragment. On ne peut que se demander pourquoi les développeurs Android ne l'ont pas fourni avec un getter. Cette variable est instanciée dans la setPrimaryItem()méthode. Donc, remplacez cette méthode de manière à obtenir la référence à cette variable. J'ai simplement fini par déclarer le mien mCurrentPrimaryItemet copier le contenu desetPrimaryItem() mon surpassement.

Dans votre implémentation de FragmentStatePagerAdapter:

private Fragment mCurrentPrimaryItem = null;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;
    if (fragment != mCurrentPrimaryItem) {
        if (mCurrentPrimaryItem != null) {
            mCurrentPrimaryItem.setMenuVisibility(false);
            mCurrentPrimaryItem.setUserVisibleHint(false);
        }
        if (fragment != null) {
            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
        }
        mCurrentPrimaryItem = fragment;
    }
}

public TasksListFragment getCurrentFragment() {
    return (YourFragment) mCurrentPrimaryItem;
}
Sevastyan Savanyuk
la source
2

Vous pouvez définir PagerAdaptercomme cela , alors vous serez en mesure d'obtenir tout Fragmenten ViewPager.

private class PagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

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

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }
}

Pour obtenir le courant Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());
Phan Van Linh
la source
2

Lorsque nous utilisons le viewPager, un bon moyen d'accéder à l'instance de fragment en activité est instantiateItem (viewpager, index). // index- index du fragment dont vous voulez l'instance.

par exemple, j'accède à l'instance de fragment de 1 index-

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}
Chahat Jain
la source
2

Dans mon implémentation précédente, j'ai stocké une liste de fragments enfants pour pouvoir y accéder plus tard, mais cela s'est avéré être une implémentation incorrecte provoquant d'énormes fuites de mémoire.

Je instantiateItem(...)finis par utiliser la méthode pour obtenir le fragment actuel:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

Ou pour obtenir n'importe quel autre fragment en position:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

De la documentation :

Créez la page pour la position donnée. L'adaptateur est responsable de l'ajout de la vue au conteneur indiqué ici, mais il doit uniquement s'assurer que cela est fait au moment où il revient de finishUpdate (ViewGroup).

Micer
la source
Court et propre, merci
JimmyFlash
1

J'ai eu le même problème et l'ai résolu en utilisant ce code.

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

Remplacez simplement le nom MyFragment par le nom de votre fragment et ajoutez l'ID de votre conteneur de fragments.

Bilal Soomro
la source
1

C'est plus pérenne que la réponse acceptée:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    /* ------------------------------------------------------------------------------------------ */
    // region Private attributes :

    private Context _context;
    private FragmentManager _fragmentManager;
    private Map<Integer, String> _fragmentsTags = new HashMap<>();

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region Constructor :

    public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {

        super(fragmentManager);

        _context = context;
        _fragmentManager = fragmentManager;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region FragmentPagerAdapter methods :

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

    @Override
    public Fragment getItem(int position) {

        if(_fragmentsTags.containsKey(position)) {

            return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
        }
        else {

            switch (position) {

                case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
                case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
            }
        }

        return null;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        // Instantiate the fragment and get its tag :
        Fragment result = (Fragment) super.instantiateItem(container, position);
        _fragmentsTags.put(position, result.getTag());

        return result;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */
}
Tim Autin
la source
Vous devriez plutôt utiliser WeakHashMap.
Prakash Nadar
1

Le scénario en question est mieux servi par chaque fragment ajoutant ses propres éléments de menu et traitant directement onOptionsItemSelected (), comme décrit dans la documentation officielle . Il vaut mieux éviter les trucs non documentés.

Y2i
la source
Cette réponse pourrait utiliser plus de détails pour savoir comment procéder. Comment l'ajout d'un élément de menu résout-il le ViewPagerproblème?
Suragch
Le problème @Suragch ViewPager existe si les événements de menu sont gérés dans Activity qui héberge des fragments et n'existe pas si les événements sont gérés dans le fragment lui-même. Le lien montre comment un fragment peut ajouter ses propres éléments de menu.
Y2i
1

Après avoir lu tous les commentaires et réponses, je vais vous expliquer une solution optimale pour ce problème. La meilleure option est la solution de @ rik, donc mon amélioration est basée sur la sienne.

Au lieu d'avoir à demander à chaque FragmentClass comme

if(FragmentClass1){
   ...
if(FragmentClass2){
   ...
}

Créez votre propre interface et faites en sorte que vos fragments enfants l'implémentent, quelque chose comme

public interface MyChildFragment {
    void updateView(int position);
}

Ensuite, vous pouvez faire quelque chose comme ça pour lancer et mettre à jour vos fragments internes.

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

PS Faites attention où vous mettez ce code, si vous appelez insatiateItem avant que le système ne le crée réellement, le savedInstanceStatefragment de votre enfant sera nul à cet effet

public void onCreate(@Nullable Bundle savedInstanceState){
      super(savedInstanceState)
}

Va planter votre application.

Bonne chance

Pedro Varela
la source
1

Sur la base de ce qu'il a répondu @chahat jain:

"Lorsque nous utilisons le viewPager, un bon moyen d'accéder à l'instance de fragment en activité est instantiateItem (viewpager, index). // index- index du fragment dont vous voulez l'instance."

Si vous voulez le faire en kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 à l'instance de fragment de 0

// ================================================= ========================= // // ###################### ######## Exemple d'utilisation ################################# // // == =================================================== ===================== //

Voici un exemple complet pour avoir une vision des plus

voici mon veiewPager dans le fichier .xml

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

Et l'activité à domicile où j'insère l'onglet

...
import kotlinx.android.synthetic.main.movie_tab.*

class HomeActivity : AppCompatActivity() {

    lateinit var  adapter:HomeTabPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    }



    override fun onCreateOptionsMenu(menu: Menu) :Boolean{
            ...

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
          ...

            override fun onQueryTextChange(newText: String): Boolean {

                if (mv_viewpager.currentItem  ==0)
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                    if ( fragment is ListMoviesFragment)
                        fragment.onQueryTextChange(newText)
                }
                else
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
                    if ( fragment is ListShowFragment)
                        fragment.onQueryTextChange(newText)
                }
                return true
            }
        })
        return super.onCreateOptionsMenu(menu)
    }
        ...

}
DINA TAKLIT
la source
0

Dans mon activité, j'ai:

int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int pos) {
        currentPage = pos;//update current page
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageScrollStateChanged(int arg0) {}
});



@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);
    if(fragment instanceof Fragment1)
        fragments.put(0, fragment);
    if(fragment instanceof Fragment2)
        fragments.put(2, fragment);
    if(fragment instanceof Fragment3)
        fragments.put(3, fragment);
    if(fragment instanceof Fragment4)
        fragments.put(4, fragment);
}

Then I have the following method for getting the current fragment

public Fragment getCurrentFragment() {
    return fragments.get(currentPage);
}
J. Musyoka
la source
0
final ViewPager.OnPageChangeListener onPageChangeListener =
    new ViewPager.OnPageChangeListener() {
      @Override public void onPageSelected(int position) {
        switch (position) {
          case 0:
            FragmentClass1 frag1 =
                (FragmentClass1) viewPager.getAdapter()
                    .instantiateItem(viewPager, viewPager.getCurrentItem());
            frag1.updateList("Custom text");
            break;
          case 1:
            break;
          case 2:
            break;
        }
      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

      }

      @Override public void onPageScrollStateChanged(int state) {
      }
    };


 viewPager.addOnPageChangeListener(onPageChangeListener);

viewPager.setAdapter(adapter);


viewPager.post(new Runnable() {
  @Override public void run() {
    onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
  }
});

Parfois, le fragment peut envoyer un objet nul, vous pouvez donc exécuter un nouveau Runnable pour résoudre le problème au premier chargement.

Merci rick

Benjamín Rengifo
la source
Veuillez ajouter du texte expliquant pourquoi ce code résoudrait le problème de l'OP. En outre, compte tenu du nombre d'autres réponses, expliquez pourquoi cette réponse est meilleure que celles déjà données. Aidez les autres à comprendre.
APC
0

Remplacez setPrimaryItem de votre FragmentPagerAdapter: l'objet est le fragment visible:

 @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (mCurrentFragment != object) {
                mCurrentFragment = (LeggiCapitoloFragment) object;
            }
            super.setPrimaryItem(container, position, object);
        }
Flavio Barisi
la source
0

Obtenez simplement l'élément actuel du téléavertisseur, puis demandez à votre adaptateur le fragment de cette position.

 int currentItem = viewPager.getCurrentItem();
    Fragment item = mPagerAdapter.getItem(currentItem);
    if (null != item && item.isVisible()) {
       //do whatever want to do with fragment after doing type checking
        return;
    }
Pankaj kumar
la source
3
Et si getItemcrée une nouvelle instance
Prakash Nadar
0

Pour obtenir le fragment actuel - obtenez la position dans ViewPager à public void onPageSelected (position int finale) , puis

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

SECTNUM - argument de position affecté dans public PlaceholderFragment statique newInstance (int sectionNumber);de fragment

getChildFragmentManager () ou getFragmentManager () - dépend de la façon dont SectionsPagerAdapter a été créé

Evgeny
la source
0

Vous pouvez implémenter un BroadcastReceiver dans le fragment et envoyer une intention de n'importe où. Le récepteur du fragment peut écouter l'action spécifique et invoquer la méthode de l'instance.

Une mise en garde consiste à s'assurer que le composant View est déjà instancié et (et pour certaines opérations, telles que le défilement d'une liste, le ListView doit déjà être rendu).

nichole
la source
0

C'est le hack le plus simple:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(code kotlin)

Appelez-le instantiateItem(viewPager, viewPager.getCurrentItem()et lancez-le Fragment. Votre article serait déjà instancié. Pour être sûr, vous pouvez ajouter un chèque pourgetCount .

Fonctionne avec les deux FragmentPagerAdapteret FragmentStatePagerAdapter!

vedant
la source
0

Si votre téléavertisseur se trouve dans un fragment, utilisez ceci:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

R.id.myViewPagerIdest l'ID de votre ViewPager dans la mise en page XML.

vovahost
la source
Cela ne fonctionne qu'avec FragmentPageAdapter normal et non avec FragmentStatePageAdapter.
progNewbie
0

Vous pouvez déclarer un tableau de fragments en tant que fragments de registre

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Ensuite, vous pouvez l'utiliser comme

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}
Hamza Khan
la source
Si vous décidez de suivre cette voie, vous devez également implémenter destroyItem () et supprimer l'instance détruite de RegisteredFragments, sinon vous aurez une fuite de mémoire.
dephinera
Voilà de bons conseils. Vous êtes invités à apporter une modification dans la réponse.
Hamza Khan
stackoverflow.com/questions/55728719/… check this out
Atif AbbAsi