J'ai une application avec un ViewPager
et trois Fragment
s. 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?
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".
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);
}
}
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
Oui, c'est possible si vous utilisez FragmentStatePagerAdapter
.
ViewPager vp;
//...
YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem());
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 ViewPager
OnPageChangeListener
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
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();
}
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;
}
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
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é.
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);
}
}