web-dev-qa-db-fra.com

Android obtention d'un fragment qui se trouve dans FragmentPagerAdapter

J'ai le problème suivant: J'ai une activité dans laquelle j'ai deux onglets qui sont faits à la fois en tant que fragments en utilisant FragmentPagerAdapter Dans un instant, je voudrais changer la vue de l'un de ces fragments, mais je ne suis pas en mesure à findFragmentById () ou findFragmentByTag () Je ne peux pas définir d'ID, car je ne déclare pas Fragment en XML, à cause de FragmentPagerAdapter Et lorsque j'essaie de définir la balise, j'obtiens le problème suivant:

08-15 21:46:23.805: E/AndroidRuntime(9297): Java.lang.IllegalStateException: Can't  change tag of fragment Companies{416d7b78 id=0x7f04002e companies}: was companies now Android:switcher:2130968622:1

Mon code du pager FragmentPagerAdapter:

public class TabsAdapter extends FragmentPagerAdapter implements    ActionBar.TabListener, ViewPager.OnPageChangeListener {
    private final FragmentActivity mContext;
    private final ActionBar mActionBar;
    private final ViewPager mViewPager;
    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();


    final class TabInfo {
        private final Class<?> clss;
        private final Bundle args;

        TabInfo(Class<?> _class, Bundle _args) {
            clss = _class;
            args = _args;
        }
    }

    public TabsAdapter(SherlockFragmentActivity 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 int getCount() {
        return mTabs.size();
    }

    @Override
    public Fragment getItem(int position) {
        TabInfo info = mTabs.get(position);
        FragmentTransaction ft=mContext.getSupportFragmentManager().beginTransaction();
        Fragment fragment=Fragment.instantiate(mContext, info.clss.getName(), info.args);

        if(position==1){
            ft.add(mViewPager.getId(), fragment, "companies");
        }else{
            ft.add(mViewPager.getId(), fragment);
        }
        Log.v("FRAGMENT ID", "fragment tag: "+fragment.getTag());
        ft.commit();
        Log.v("FRAGMENT ID", "fragment tag: "+fragment.getTag());
        return fragment;
    }

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

    @Override
    public void onPageSelected(int position) {
        mActionBar.setSelectedNavigationItem(position);
        new Thread(new Runnable() {

            @Override
            public void run() {
                MainActivity.this.hideKeyboard();

            }
        }).start();

    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

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


    }

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


    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }
}

Merci d'avance pour vos réponses.

34
ziky90

Les fragments fournis par FragmentPagerAdapter sont marqués automatiquement lorsqu'ils sont instanciés. Vous pouvez récupérer la balise avec cette méthode:

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

Référence: réutilisation de fragments dans un fragmentpageradapter

52
DeeV

Avec cette fonction, vous pouvez trouver le fragment par position de l'adaptateur de téléavertisseur.

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

Exemple de code pour l'API de support v4.

22
Daniel De León

J'ai trouvé un moyen un peu moins brut pour obtenir une poignée sur un Fragment créé par un FragmentPagerAdapter. Au lieu d'imiter la façon dont les balises sont créées, remplacez instantiateItem(), récupérez le Fragment renvoyé par la superclasse et enregistrez la balise dans TabInfo. Cela fonctionne pour moi sur API> = 15, peut fonctionner avec une valeur inférieure. Cela fait encore quelques hypothèses sur le code privé.

static final class TabInfo {
    private final Class<?> clss;
    private final Bundle args;
    private String tag; // ** add this

    TabInfo(Class<?> _class, Bundle _args) {
        clss = _class;
        args = _args;
    }
}


@Override
public Object instantiateItem(ViewGroup container, int position) {
    final Fragment fragment = (Fragment) super.instantiateItem(container, position);
    final TabInfo info = mTabs.get(position);
    info.tag = fragment.getTag(); // set it here
    return fragment;
}

Ou dans l'API <16, je pense que instantiateItem() prend un View() au lieu de ViewGroup(), comme ceci:

public Object instantiateItem(View container, int position);

Ensuite, autorisez un moyen d'obtenir le Fragment, en gardant le hack contenu.

public Fragment getFragment(int index) {
    return mContext.getFragmentManager().findFragmentByTag(mTabs.get(index).tag);
}

Pour que cela fonctionne, la déclaration de mContext doit être remplacée par Activity, elle est transmise en tant que Activity de toute façon:

private final Activity mContext;
6
nash

Une approche plus simple consiste à obtenir les balises directement à partir du gestionnaire de fragments; comme ça:

fm.getFragments().get(0).getTag()

Vous pouvez remplacer la position, selon le fragment pour lequel vous avez besoin de la balise. J'espère que cela aide les autres!.

1
Chriss Villegas