5

Sto usando viewpager per visualizzare le immagini. Ho solo bisogno di tre frammenti fondamentalmente: l'immagine precedente per l'anteprima, l'immagine corrente del display e l'immagine successiva per l'anteprima. Mi piacerebbe solo visualizzare un'anteprima dell'immagine precedente e successiva, cambierà a immagine intera quando l'utente lo farà effettivamente scorrere. Quindi sto pensando di usare solo 3 frammenti per raggiungere questo obiettivo. Codice è qui sotto:Frammento già aggiunto IllegalStateException in viewpager

private class ImagePagerAdapter extends FragmentStatePagerAdapter implements ViewPager.OnPageChangeListener { 
    private ImageFragment mImageFragment; 
    private ImagePreviewFragment mPreviousPreviewFragment; 
    private ImagePreviewFragment mNextPreviewFragment; 

    public ImagePagerAdapter(FragmentManager fm, ImageFragment image, ImagePreviewFragment previous, ImagePreviewFragment next) { 
     super(fm); 
     mImageFragment = image; 
     mPreviousPreviewFragment = previous; 
     mNextPreviewFragment = next; 
    } 

    @Override 
    public Fragment getItem(int position) { 
     if (position == mPager.getCurrentItem()) { 
      mImageFragment.display(position); 
      return mImageFragment; 
     } 

     if (position < mPager.getCurrentItem()) { 
      mPreviousPreviewFragment.display(position - 1); 
      return mPreviousPreviewFragment; 
     } 
     mNextPreviewFragment.display(position + 1); 
     return mNextPreviewFragment; 
    } 


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

    @Override 
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
     Log.d(TAG, "onPageScrolled"); 
    } 

    @Override 
    public void onPageSelected(final int position) { 
     Log.d(TAG, "onPageSelected " + position); 
     new Handler().postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       notifyDataSetChanged(); 
      } 
     }, 500); 
    } 


    @Override 
    public void onPageScrollStateChanged(int state) { 
     Log.d(TAG, "onPageScrollStateChanged " + state); 
    } 

    @Override 
    public int getItemPosition(Object item) { 
     return POSITION_NONE; 
     //return POSITION_UNCHANGED; 
    } 
} 

Quindi, in pratica, ho pre-creato tre frammenti per visualizzare precedente/successiva immagine corrente di anteprima e e restituirli per getItem(). Ho anche notifydatasetchange() in onpageselected() per fare tutte e tre le posizioni per aggiornare il frammento quando l'utente passa alla nuova pagina.

Ma il problema è che sarà buttare fuori

Fragment already added IllegalStateException 

quando i frammenti sono aggiunte una seconda volta. Penso che sia perché è stato aggiunto prima. Posso creare ogni volta un nuovo frammento, ma penso che sia uno spreco. Quindi, come posso riutilizzare il frammento già creato e aggiornarlo?

Grazie, Simon

risposta

2

FragmentStatePagerAdapter Design propone la creazione di una nuova Fragment per ogni pagina (see Google's example). E sfortunatamente non puoi leggere un Fragment una volta aggiunto a un FragmentManager (cosa che accade implicitamente all'interno dell'adattatore), quindi l'eccezione che stai affrontando. Quindi il modo ufficiale di Google è creare nuovi frammenti e lasciarli distruggere e ricreare dall'adattatore.

Ma se si desidera riutilizzare le pagine e utilizzare un modello analogico di ViewHolder, è necessario attenersi alle visualizzazioni anziché ai frammenti. Le viste possono essere rimosse dai loro genitori e riutilizzate, a differenza dei frammenti. Estendere PagerAdapter e implementare instantiateItem() come questo:

@Override 
public Object instantiateItem(ViewGroup container, final int position) { 
    //determine the view type by position 
    View view = viewPager.findViewWithTag("your_view_type"); 
    if (view == null) { 
     Context context = container.getContext(); 
     view = LayoutInflater.from(context).inflate(R.layout.page, null); 
     view.setTag("your_view_type"); 
    } else { 
     ViewGroup parent = (ViewGroup) item.getParent(); 
     if (parent != null) { 
      parent.removeView(item); 
     } 
    } 
    processYourView(position, view); 
    container.addView(view, MATCH); 
    return view; 
} 

si dovrebbe aggiungere un po 'di logica in più per determinare il tipo di visualizzazione in base alla posizione (poiché avete 3 tipi di punti di vista), penso che si può capirlo.

Problemi correlati