web-dev-qa-db-fra.com

Les éléments d'action du fragment initial de Viewpager ne sont pas affichés

Dans l'application que je développe, j'utilise un ViewPager avec des fragments et chaque fragment construit son propre menu indépendamment de tous les autres fragments du ViewPager.

Le problème est que, parfois, les éléments initialisés par défaut par ViewPager (c'est-à-dire dans son état initial) ne voient pas leurs éléments renseignés dans le menu des éléments d'action. Ce qui est pire, c'est que ce problème ne se produit que par intermittence. Si je glisse suffisamment dans le ViewPager pour que les fragments soient forcés de se réinitialiser, le menu se remplit correctement lorsque je recule.

Code d'activité:

package net.solarnz.apps.fragmentsample;

import Android.app.Activity;
import Android.app.Fragment;
import Android.app.FragmentManager;
import Android.os.Bundle;
import Android.support.v13.app.FragmentStatePagerAdapter;
import Android.support.v4.view.ViewPager;

public class FragmentSampleActivity extends Activity {
    private ViewPagerAdapter mViewPagerAdapter;
    private ViewPager mViewPager;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        if (mViewPagerAdapter == null) {
            mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager());
        }

        mViewPager = (ViewPager) findViewById(R.id.log_pager);
        mViewPager.setAdapter(mViewPagerAdapter);
        mViewPager.setCurrentItem(0);
    }


    private class ViewPagerAdapter extends FragmentStatePagerAdapter {
        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

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

        @Override
        public Fragment getItem(int position) {
            Fragment f = Fragment1.newInstance(position);
            // f.setRetainInstance(true);
            f.setHasOptionsMenu(true);
            return f;
        }
    }
}

Code de fragment:

package net.solarnz.apps.fragmentsample;

import Android.app.Fragment;
import Android.os.Bundle;
import Android.view.Menu;
import Android.view.MenuInflater;

public class Fragment1 extends Fragment {
    int mNum;

    static Fragment newInstance(int num) {
        Fragment1 f = new Fragment1();

        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putInt("num", num);
        f.setArguments(args);

        return f;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        mNum = getArguments() != null ? getArguments().getInt("num") : 0;
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_list, menu);
    }

}

Disposition:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"

    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent" >

            <Android.support.v4.view.ViewPager
                Android:id="@+id/log_pager"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent" />
</LinearLayout>

Menu:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:id="@+id/menu_refresh"
          Android:title="Refresh"
          Android:icon="@Android:drawable/ic_delete"
          Android:showAsAction="ifRoom|withText" />
</menu>

Menu d'action en cours de remplissage: http://i.stack.imgur.com/QFMDd.png

Menu d'action non renseigné: http://i.stack.imgur.com/sH5Pp.png

29
solarnz

Vous devriez lire ceci (par xcolw ...)

Après expérimentation, il semble que la cause principale soit invalidateOptionsMenu, car elle est appelée plus d’une fois sans interruption sur le thread principal pour traiter les travaux en attente. Une hypothèse - cela aurait de l'importance si une partie essentielle de la création de menu était différée via un post, laissant la barre d'action en mauvais état jusqu'à son exécution.

Cela peut arriver à quelques endroits qui ne sont pas évidents:

  1. appelant viewPager.setCurrentItem plusieurs fois pour le même élément

  2. appeler viewPager.setCurrentItem dans onCreate de l'activité. setCurrentItem provoque l'invalidation d'un menu d'options, immédiatement suivi de l'invalidation du menu d'options de l'activité.

Solutions que j'ai trouvées pour chaque

  1. Garde l'appel à viewPager.setCurrentItem

    if (viewPager.getCurrentItem() != position)
        viewPager.setCurrentItem(position);
    
  2. Reporter l'appel à viewPager.setCurrentItem dans onCreate

    public void onCreate(...) {
        ...
        view.post(new Runnable() {
            public void run() {
                // guarded viewPager.setCurrentItem
            }
        }
    }
    

Après ces modifications, le menu d’options à l’intérieur du visualiseur semble fonctionner comme prévu. J'espère que quelqu'un pourra nous éclairer davantage.

sourcehttp://code.google.com/p/Android/issues/detail?id=29472

21
Wayne

La réponse simple est de ne pas utiliser les menus au sein de fragments dans ViewPager. Si vous devez utiliser des menus dans les fragments, je vous suggère de les charger via la méthode onCreateOptionsMenu dans l'activité parent. De toute évidence, vous devrez être en mesure de déterminer quel menu afficher.

J'ai pu réaliser cela en utilisant la réflexion en classe. Vous devrez également utiliser la méthode invalidateOptionsMenu chaque fois que vous changez de page. Vous aurez besoin d'un OnPageChangeListener pour l'appeler lorsque ViewPager change de page.

8
solarnz

J'ai aussi eu le même problème. Dans mon cas, j'ai une activité avec viewpager qui contient deux fragments, chaque fragment gonflant son propre menu d'actions mais le menu d'actions de fragments non affiché.

Afficher le code de l'adaptateur de téléavertisseur

 public class ScreensAdapter extends FragmentPagerAdapter {

    public TrackerScreensAdapter(Context context, FragmentManager fm) {
        super(fm);
    }

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

    public Fragment getItem(int position) {
        Fragment fragment = null;
        switch (position){
            case 0:
                fragment = new Fragment1();
                break;
            case 1:
                fragment = new Fragment2();
                break;
        }
        return fragment;
    }

}

Activité sur créer

    screensAdapter = new ScreensAdapter(this, getFragmentManager());
    viewPager.setAdapter(screensAdapter);

De cette façon, mon viewPager a deux fragments, chaque fragment lance sa propre tâche dans onActivityCreated, obtient des données et dessine sa présentation en fonction des données obtenues. De plus, chaque fragment a onCreateOptionsMenu

  @Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);
    MyTask task = new MyTask();
    task.setTaskListener(this);
    task.execute();


}

 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.fragment_menu, menu);
}

J'ai passé plusieurs fois à résoudre ce problème et à comprendre pourquoi le menu de fragments ne s'affiche pas. Tout ce dont j'avais besoin, c'est

    screenAdapter = new ScreenAdapter(this, getFragmentManager());
    viewPager.post(new Runnable() {
        public void run() {
            viewPager.setAdapter(screenAdapter);
        }
    });
3
Georgy Gobozov

Commencez par créer une méthode dans la sous-classe de FragmentPagerAdapter pour obtenir le fragment en cours.

    public SherlockFragment getFragment() {
    return currentFragment;
}

        @Override
public void onTabSelected(final Tab tab, FragmentTransaction ft) {

    ((SherlockFragmentActivity) mContext).invalidateOptionsMenu();
    Fragment f = ((SherlockFragmentActivity) mContext)
            .getSupportFragmentManager().findFragmentByTag(
                    makeFragmentName(tab.getPosition()));

    currentFragment=(SherlockFragment) f;
 }

Maintenant, remplacez les méthodes ci-dessous dans Actvity principale

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (mTabsAdapter.getPositionOfTabSelected() != 0) {
        menu.add("Read").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.add("Write").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.add("Clear").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.add("Factory data reset").setShowAsAction(
                MenuItem.SHOW_AS_ACTION_IF_ROOM);
    }

    return super.onCreateOptionsMenu(menu);
}

Appelez maintenant onOptionItemSelected d'activité en fragment

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    mTabsAdapter.getFragment().onOptionsItemSelected(item);
    return super.onOptionsItemSelected(item);
}
0
Deepak Goel

J'avais ce problème avec les éléments de la barre d'action lorsque j'utilisais HorizontalScrollView pour afficher les onglets, mais j'ai changé pour PagerTitleStrip et le problème a été résolu.

Peut-être que cette information peut aider quelqu'un d'autre.

0
Jose M Lechon

Dans mon cas, la cause du problème a été attribuée à ce que je considère être un bogue dans FragmentStatePagerAdapter qui appelle Fragment # setMenuVisibility à false et ne parvient pas à le redéfinir correctement lorsqu'il restaure son état.

Solutions de contournement:

  1. Utilisez FragmentPagerAdapter au lieu de FragmentStatePagerAdapter

  2. Si vous devez utiliser FragmentStatePagerAdapter, dans votre sous-classe d'adaptateur, remplacez setPrimaryItem de la manière suivante:

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
    
        //This is a workaround for a bug in FragmentStatePagerAdapter
        Fragment currentItem = getItem(position);
        if (currentItem != null) {
            currentItem.setMenuVisibility(true);
            currentItem.setUserVisibleHint(true);
        }
    }
    
0
Ilan Klinghofer

J'ai résolu un problème très similaire dans lequel les icônes de la barre d'action attribuées par le fragment à l'intérieur d'un ViewPager disparaissaient de onPause (). Ils réapparaîtront lorsque le fragment reviendra à la vue et que l'utilisateur effectuera un balayage à gauche ou à droite, mais pas immédiatement. La solution appelait notifyDataSetChanged () sur le PagerAdapter de la méthode onResume () du fragment.

@Override
public void onResume() {
    mPagerAdapter.notifyDataSetChanged();
}
0
Matt W