2012-09-07 24 views

Respuesta

31

Sí. Trataré de responder su caso mostrando cómo lo hice, y mostraré un ejemplo para su caso debajo de mi muestra del código.

Básicamente, para lograr esto, debe hacer un seguimiento de la posición de los Fragmentos. A continuación se muestra la implementación que utilicé para mi FragmentPagerAdapter, que utiliza una ArrayList como fuente de datos.

public class MyFragmentPagerAdapter extends FragmentPagerAdapter { 

    private HashMap<Long, Fragment> mItems 
        = new HashMap<Long, Fragment>(); 

    private ArrayList<MyObject> dataset; 

    public MyFragmentPagerAdapter(ArrayList<MyObject> objects) { 
     this.dataset = objects; 
    } 

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

    @Override 
    public Fragment getItem(int position) { 
     long id = getItemId(position); 

     if(mItems.get(id) != null) { 
      // caching to prevent multiple instances of the same fragment 
      // for the same position/id 
      return mItems.get(id); 
     } 

     Fragment f = Fragment.newInstance(); 

     mItems.put(id, f); 

     return f; 
    } 

    @Override 
    public long getItemId(int position) { 
     // return a unique id 
     return dataset.get(position).getUniqueId(); 
    } 

    @Override 
    public int getItemPosition(Object object) { 
     /* 
     * Purpose of this method is to check whether an item in the adapter 
     * still exists in the dataset and where it should show. 
     * For each entry in dataset, request its Fragment. 
     * 
     * If the Fragment is found, return its (new) position. There's 
     * no need to return POSITION_UNCHANGED; ViewPager handles it. 
     * 
     * If the Fragment passed to this method is not found, remove all 
     * references and let the ViewPager remove it from display by 
     * by returning POSITION_NONE; 
     */ 
     Fragment f = (Fragment) object; 

     for(int i = 0; i < getCount(); i++) { 

      Fragment item = (Fragment) getItem(i); 
      if(item.equals(f)) { 
       // item still exists in dataset; return position 
       return i; 
      } 
     } 

     // if we arrive here, the data-item for which the Fragment was created 
     // does not exist anymore. 

     // Also, cleanup: remove reference to Fragment from mItems 
     for(Map.Entry<Long, MainListFragment> entry : mItems.entrySet()) { 
      if(entry.getValue().equals(f)) { 
       mItems.remove(entry.getKey()); 
       break; 
      } 
     } 

     // Let ViewPager remove the Fragment by returning POSITION_NONE. 
     return POSITION_NONE; 
    } 
} 

Ahora bien, si se elimina un elemento del conjunto de datos (this.dataset) y llamar notifyDataSetChanged() en la instancia de MyFragmentPagerAdapter, eliminará el elemento de la ViewPager (incluso si es que se está viendo actualmente).

Digamos this.dataset contiene 5 elementos y desea mover el n. ° 2 al final de la ViewPager. Para lograr esto, tendrá que posicionar el ítem n. ° 2 al final de su fuente de datos (ya sea a través del Collection.Sort o de alguna otra manera). Te mostraré la manera fácil.

ArrayList<MyObject> list = new ArrayList<>(); 
MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(list); 
viewpager.setAdapter(adapter); 

... 

MyObject item = list.get(2); 
list.remove(item); 
list.add(item); // now it's positioned at the end of the list 
adapter.notifyDataSetChanged(); // voilá, that should do the trick! 

adapter.notifyDataSetChanged() llama finalmente viewpager.dataSetChanged(), que a su vez llama a adapter.getItemPosition(..) en cada una de sus páginas. El resultado de esa llamada al método determina si y dónde aparecerá la página (Fragmento en este caso).

+1

Muy comprensible. ¿Alguna razón por la que no está utilizando un FragmentStatePagerAdapter con esta implementación? ¿Sus listas de artículos harán que la clase a gran escala pierda todas las razones de su usabilidad? – jbenowitz

+0

Esto tampoco pareció ayudarme. Estoy eliminando elementos, en total. Cada vez que fui al siguiente artículo, eliminé el elemento anterior, se deslizaría pero a mitad de deslizar cambiaría el siguiente ítem para que fuera el ítem después de eso. Visualmente: A, B, C elementos en el adaptador Vista A, deslice hacia B. Comience eliminando A, pase hacia la mitad B, Destello hacia C. – jbenowitz

+0

Sí, esto es esperado. Si elimina A, B será pos == 0 y C pos == 1. Su elemento actual ('viewPager.setCurrentItem (int)') se establece en 1 al deslizar de A a B. Cuando elimina A, la posición actual seguirá siendo 1, lo que significa que 'ViewPager' saltará a C.Puede corregir esto estableciendo 'viewPager.setCurrentItem (adapter.getItemPosition (fragment-B))' cuando elimine A. – Reinier

1

Acabo de leer todo esto.

La forma habitual de usar un ViewPager es tener una clase PagerAdapter que lo alimente con las páginas correctas en el momento correcto. Existen bonitas subclases de PagerAdapter, FragmentPagerAdapter y FragmentStatePagerAdapter, que son más fáciles de usar.

Sin embargo, para poder cambiar el orden de las páginas, tendrá que escribir su propia subclase de PagerAdapter. Básicamente, hay dos maneras en que ViewPager sabe en qué página está: el número de página y un objeto clave que el adaptador le ha proporcionado. Por lo tanto, debe poder cambiar el orden sin que ViewPager se pierda demasiado.

Los detalles sangrientos de cómo se hace están en this page. Todavía no lo he intentado, pero lo haré en las próximas semanas. Creo que esa página no dice todo. No menciona el método getItem() que deben tener la mayoría de las clases de Adapter. Así que realmente todavía no veo cómo se agregan las páginas a ViewPager.

Tiempo para buscar y leer algunos ejemplos de código.

Cuestiones relacionadas