2012-04-11 11 views
9

Robię aplikację adroid z viewpager i fragmentami. Chcę utworzyć opcję dynamicznego dodawania lub usuwania stron fragmentów do pager'a. Mam zwyczaj FragmentPagerAdapter:wstawianie i usuwanie fragmentów w viewpager poprawnie

public class MyAdapter extends FragmentPagerAdapter implements TitleProvider{ 

    protected final List<PageFragment> fragments; 

    /** 
    * @param fm 
    * @param fragments 
    */ 
    public MyAdapter(FragmentManager fm, List<PageFragment> fragments) { 

     super(fm); 
     this.fragments = fragments; 
    } 

    public void addItem(PageFragment f){ 
     fragments.add(f); 
     notifyDataSetChanged(); 
    } 

    public void addItem(int pos, PageFragment f){ 
     for(int i=0;i<fragments.size();i++){ 
      if(i>=pos){ 
       getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(i))).commit(); 
      } 
     } 
     fragments.add(pos,f); 
     notifyDataSetChanged(); 
     pager.setAdapter(this); 
     pager.setCurrentItem(pos); 

    } 

    public void removeItem(int pos){ 
     getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(pos))).commit(); 
     for(int i=0;i<fragments.size();i++){ 
      if(i>pos){ 
       getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(i))).commit(); 
      } 
     } 
     fragments.remove(pos); 

     notifyDataSetChanged(); 
     pager.setAdapter(this); 
     if(pos<fragments.size()){ 
      pager.setCurrentItem(pos); 
     }else{ 
      pager.setCurrentItem(pos-1); 
     } 
    } 



    @Override 
    public Fragment getItem(int position) { 
     return fragments.get(position).toFragment(); 
    } 

    @Override 
    public int getCount() { 
     return fragments.size(); 
    } 

    @Override 
    public int getItemPosition(Object object) { 
     return POSITION_NONE; 
    } 

    private String getFragmentTag(int pos){ 
     return "android:switcher:"+R.id.pager+":"+pos; 
    } 

    public String getTitle(int position) { 
     String name = fragments.get(position).getName(); 
     if(name.equals("")) 
      return "- "+position+" -"; 
     return name; 
    } 
} 

mogę usunąć dowolny fragment z wyjątkiem 0. gdy próbuję usunąć go mam NullPointerException na notifyDataSetChanged(); lub na pager.setAdapter (ten); jeśli skomentuję powiadomienie.

Dostałem również wyjątek NullPointerException, gdy próbuję wstawić nową stronę. Kiedy dodaję nową stronę do końca listy, to działa dobrze. Próbowałem nawet ponownie dodać fragmenty we wkładce z tym po fragments.add (poz, f)

for(int i=0;i<fragments.size();i++){ 
      if(i>=pos){ 
       getSupportFragmentManager().beginTransaction().add(fragments.get(i).toFragment(),getFragmentTag(i-1)).commit(); 
      } 
     } 

jeśli używam getFragmentTag(i-1) mam NullPointer ponownie. Przy użyciu tylko i otrzymałem niedozwolony wyjątek wyjątku, ponieważ nie można zmodyfikować znacznika fragmentu. Z beginTransaction().add(pager.getId,fragments.get(i).toFragment()) nadal jest nullpointer ...

Moje pytanie brzmi: co robię źle i jak można to zrobić właściwie? (i być może: skąd notyfyDataSetChanged() pobierają dane, gdy powodują punkt zerowy zerowy?)

Odpowiedz

1

Mam rozwiązanie, które działa z adapterem bez fragmentów. Spójrz na my post i sprawdź, czy to pomaga.

+1

Odpowiedzi dotyczące wyłącznie linków nie są zalecane. –

0

mogę usunąć dowolny fragment z wyjątkiem 0.

dla mnie to działa, jeśli po prostu użyć> = stan wzięciu removeItem dla pętli:

 if (i >= pos){ 
      fm.beginTransaction().remove(fragments.get(i).getFragment()).commit(); 
     } 
7

To właśnie rozwiązałem problem z zaznaczaniem fragmentów podczas tworzenia instancji i faktem, że wcześniej zaznaczone fragmenty nie mogą zmienić pozycji w ViewPager podczas próby dodawania lub wyjmowania kartek, tj się wyjątek:

java.lang.IllegalStateException: nie można zmienić znacznik fragmentu MyFragment {4055f558 id = 0x7f050034 ANDROID przełącznika: 2131034164: 3} był ANDROID przełącznika : 2131034164: 3 teraz android: przełącznik: 2131034164: 4

adapter ten jest tworzony z listą wszystkich stron góry i można następnie wykorzystać setEnabled (int pozycję, logiczna włączone) aby włączyć lub wyłączyć niektóre strony która ukrywa lub pokazuje te strony w ViewPager.

Działa, utrzymując wewnętrzną listę wszystkich fragmentów, ale wystawiając na ViewPager i odwzorowując tylko pozycje włączonych fragmentów.

public class DynamicFragmentPagerAdapter extends FragmentPagerAdapter { 

    public final ArrayList<Fragment> screens = new ArrayList<Fragment>(); 

    private Context context; 
    private List<AtomicBoolean> flags = new ArrayList<AtomicBoolean>(); 

    public DynamicFragmentPagerAdapter(FragmentManager fm, Context context, List<Class<?>> screens) { 
     super(fm); 
     this.context = context; 

     for(Class<?> screen : screens) 
      addScreen(screen, null); 

     notifyDataSetChanged(); 
    } 

    public DynamicFragmentPagerAdapter(FragmentManager fm, Context context, Map<Class<?>, Bundle> screens) { 
     super(fm); 
     this.context = context; 

     for(Class<?> screen : screens.keySet()) 
      addScreen(screen, screens.get(screen)); 

     notifyDataSetChanged(); 
    } 

    private void addScreen(Class<?> clazz, Bundle args) { 
     screens.add(Fragment.instantiate(context, clazz.getName(), args)); 
     flags.add(new AtomicBoolean(true)); 
    } 

    public boolean isEnabled(int position) { 
     return flags.get(position).get(); 
    } 

    public void setEnabled(int position, boolean enabled) { 
     AtomicBoolean flag = flags.get(position); 
     if(flag.get() != enabled) { 
      flag.set(enabled); 
      notifyDataSetChanged(); 
     } 
    } 

    @Override 
    public int getCount() { 
     int n = 0; 
     for(AtomicBoolean flag : flags) { 
      if(flag.get()) 
       n++; 
     } 
     return n; 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return screens.get(position); 
    } 

    @Override 
    public int getItemPosition(Object object) { 
     return POSITION_NONE; // To make notifyDataSetChanged() do something 
    } 

    @Override 
    public void notifyDataSetChanged() { 
     try { 
      super.notifyDataSetChanged(); 
     } catch (Exception e) { 
      Log.w("", e); 
     } 
    } 

    private List<Fragment> getEnabledScreens() { 
     List<Fragment> res = new ArrayList<Fragment>(); 
     for(int n = 0; n < screens.size(); n++) { 
      if(flags.get(n).get()) 
       res.add(screens.get(n)); 
     } 
     return res; 
    } 

    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     // We map the requested position to the position as per our screens array list 
     Fragment fragment = getEnabledScreens().get(position); 
     int internalPosition = screens.indexOf(fragment); 
     return super.instantiateItem(container, internalPosition); 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     Fragment fragment = getEnabledScreens().get(position); 
     if(fragment instanceof TitledFragment) 
      return ((TitledFragment)fragment).getTitle(context); 
     return super.getPageTitle(position); 
    } 

    public static interface TitledFragment { 
     public String getTitle(Context context); 
    } 
} 
+0

Działa poprawnie, ale gdy wywoływane jest 'notifyDatasetChanged', tworzy nowe widoki dla każdego' Fragment', więc tracę stan UI. Jak mogę temu zapobiec? – WonderCsabo

Powiązane problemy