web-dev-qa-db-fra.com

Est-il possible d'accéder au fragment en cours de visualisation par un ViewPager?

J'ai une application avec un ViewPager et trois Fragments. J'essaie de comprendre comment obtenir le Fragment actuel pour pouvoir consulter ses arguments. 

J'ai un OnPageChangeListener récupérant l'index de la page en cours, mais 

ViewPager.getChildAt(int position);

renvoie un View. Quelle est la relation entre ce View et le Fragment actuel?

69
MitchellSalad

J'ai finalement trouvé une réponse qui a fonctionné pour moi. Fondamentalement, vous pouvez accéder au fragment d'une page viewPager en utilisant la balise "Android: switcher:" + R.id.viewpager + ": 0". 

46
James

J'ai résolu le problème dans l'autre sens ... Au lieu de rechercher le fragment de l'activité, j'enregistre le fragment pendant qu'il est en mode onAttach () et le désenregistre dans onStop () method . Idée de base:

Fragment:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try{
        mActivity = (IMyActivity)activity;
    }catch(ClassCastException e){
        throw new ClassCastException(activity.toString() +" must be a IMyActivity");
    }

    mActivity.addFragment(this);
}

@Override
public void onStop() {
    mActivity.removeFragment(this);
    super.onStop();
}

IMyActivity:

public interface IFriendActivity {
    public void addFragment(Fragment f);
    public void removeFragment(Fragment f); 
}

Mon activité:

public class MyActivity implements IMyActivity{

    [...]

    @Override
    public void addFragment(Fragment f) {
        mFragments.add(f);
    }

    @Override
    public void removeFragment(Fragment f) {
        mFragments.remove(f);
    }

}
18
sdl

Modifier - Ne faites pas ça. Si vous êtes tenté, lisez les commentaires pour expliquer pourquoi c'est une mauvaise idée.

Il se peut que vous essayiez toujours de résoudre ce problème:

Prolonger FragmentPagerAdapter. Dans le constructeur, construisez les fragments dont vous avez besoin et stockez-les dans une liste (array/ArrayList) de fragments. 

private final int numItems = 3;
Fragment[] frags;

public SwipeAdapter (FragmentManager fm) {
    super(fm);

    //Instantiate the Fragments
    frags = new Fragment[numItems];

    Bundle args = new Bundle();
    args.putString("arg1", "foo");

    frags[0] = new MyFragment();
    frags[1] = new YourFragment();
    frags[2] = new OurFragment();
    frags[2].setArguments(args);
}

Ensuite, pour getItem(int position), vous pouvez faire quelque chose comme: 

public Fragment getItem(int position) {
    return frags[position];
}

Je ne suis pas sûr que ce soit la manière généralement acceptée de le faire, mais cela a fonctionné pour moi.

Modifier

Ce n'est vraiment pas une bonne façon de faire. Si vous envisagez de gérer les changements d'orientation ou que votre application passe en arrière-plan, cela endommagera probablement votre code. S'il vous plaît lire les commentaires ci-dessous cette réponse pour plus d'informations. Utilisez plutôt la réponse de @James

5
Mike T

Oui, c'est possible si vous utilisez FragmentStatePagerAdapter.

ViewPager vp;
//...
YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem());
4
Volodymyr Kulyk

VEUILLEZ NE PAS UTILISER CETTE

Faites en sorte que votre adaptateur étende la classe FragmentStatePagerWithCurrentAdapter suivante et au lieu d'implémenter getItem, implémentez le même code dans getItemAtIndex

Définissez ViewPagerOnPageChangeListener sur l'instance de l'adaptateur. 

Lorsque vous avez besoin d'accéder au fragment en cours, appelez simplement adapter.getCurrentItem().

package your.package;
import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.support.v4.app.FragmentStatePagerAdapter;
import Android.support.v4.view.ViewPager.OnPageChangeListener;
import Android.util.SparseArray;
import Android.view.ViewGroup;

public abstract class FragmentStatePagerWithCurrentAdapter 
extends FragmentStatePagerAdapter 
implements OnPageChangeListener {
    int currentPage = 0;

    private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();

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

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

    public abstract Fragment getItemAtIndex(int index);

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {

        super.destroyItem(container, position, object);

        mPageReferenceMap.remove(Integer.valueOf(position));
    }

    public Fragment getCurrentItem() {
        return mPageReferenceMap.get(currentPage);
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {

    }

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

    }

    @Override
    public void onPageSelected(int newPageIndex) {
        currentPage = newPageIndex;
    }

}

J'ai utilisé comme référence l'article suivant: http://tamsler.blogspot.com/2011/11/Android-viewpager-and-fragments-part-ii.html

3
Jorge Garcia

Réponse définitive qui fonctionne de manière transparente (mais petit hack):

quelque part dans la mise en page de fragment de page:

<FrameLayout Android:layout_width="0dp" Android:layout_height="0dp" Android:visibility="gone" Android:id="@+id/fragment_reference">
     <View Android:layout_width="0dp" Android:layout_height="0dp" Android:visibility="gone"/>
</FrameLayout>

dans onCreateView () de fragment: 

...
View root = inflater.inflate(R.layout.fragment_page, container, false);
ViewGroup ref = (ViewGroup)root.findViewById(R.id.fragment_reference);
ref.setTag(this);
ref.getChildAt(0).setTag("fragment:" + pageIndex);
return root;

et méthode pour retourner un fragment de ViewPager, s'il existe:

public Fragment getFragment(int pageIndex) {        
        View w = mViewPager.findViewWithTag("fragment:" + pageIndex);
        if (w == null) return null;
        View r = (View) w.getParent();
        return (Fragment) r.getTag();
}
1
Hox

Vous pouvez le faire de la manière suivante:

@Override
public Object instantiateItem(ViewGroup container, int position) {
        final Fragment frag = (Fragment) super.instantiateItem(container, position);
        if(frag instanceof ListNoteOfTypeFragment){                
            final ListNoteOfTypeFragment listNoteOfTypeFragment = (ListNoteOfTypeFragment) frag;
            //do whatever you want with your fragment here
            listNoteOfTypeFragment.setNoteChangeListener(mListener);
        }
        return frag;
    }    
1
Anh Nguyen

Cela a été expliqué ici: http://developer.Android.com/guide/topics/fundamentals/fragments.html

Dans OnCreateView, vous devez retourner une vue pour dessiner une interface utilisateur pour votre fragment. Je pense que c'est la relation.

De plus, cette question pourrait être similaire: Concentrez-vous sur ViewPager

1
Dante

FragmentStatePagerWithCurrentAdapter de Jorge Garcia est une très bonne solution, mais elle nécessite une amélioration mineure. Si l'activité est détruite et recréée en réponse à un changement de configuration ou à quelque chose du genre, getItem ne sera pas appelé pour les fragments qui ont été sauvegardés et récupérés par le gestionnaire de fragments. Donc, je substitue normalement getItem dans ma sous-classe et je mets ce qui suit dans FragmentStatePagerWithCurrentAdapter 

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object item = super.instantiateItem(container, position);
    if ( item instanceof Fragment ) {
        pageReferenceMap.put(position, (Fragment)item);
    }
    return item;
}

InstantiateItem est appelé à chaque fois que le fragment se trouvant dans cette position est accédé.

0
dmapr

Ou sauvegardez simplement tous les fragments d'une carte:

public class MyFragment extends Fragment implements OnPageChangeListener {

    private ViewPager viewPager;
    private FragmentStatePagerAdapter viewAdapter;
    private View rootView;
    private Map<Integer, Fragment> fragments = new HashMap<Integer, Fragment>();

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        rootView = inflater.inflate(R.layout.introdution, container, false);

        viewPager = (ViewPager) rootView.findViewById(R.id.pager);
        viewAdapter = new ViewAdapter(getFragmentManager());
        viewPager.setAdapter(viewAdapter);
        viewPager.addOnPageChangeListener(this);

        return rootView;

    }

    private class ViewAdapter extends FragmentStatePagerAdapter {

        public ViewAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }

        @Override
        public Fragment getItem(int position) {

            Fragment result = null;

            switch (position) {
                case 0: result = Fragment1.newInstance(); break;
                case 1: result = Fragment2.newInstance(); break;
            }

            if (result != null)
                fragments.put(position, result);

            return result;

        }

        @Override
        public int getCount() {

            return 2;
        }

    }

    @Override
    public void onPageScrollStateChanged(int arg0) {
    }

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

    @Override
    public void onPageSelected(int position) {

        Fragment currentFragment = fragments.get(position);

    }

}
0
almisoft