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.
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
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.
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;
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!.