2012-07-06 15 views
36

Como en, pueden los ELEMENTOS de un ListView ser Fragmentos. Sé que puede asignar un TextView XML a un ListView para cambiar su aspecto, pero puede agregar Fragmentos a un ListView.¿Puede un ListView contener fragmentos

Por ejemplo: Tengo un fragmento. El XML para dicho Fragment contiene un ImageView, un par de TextViews de gran estilo y un TextView pequeño. El código de clase Fragment recibe un Bundle, luego, según el contenido, rellena TextViews e ImageView en consecuencia. Tanto el Fragment XML como el código de Fragment funcionan sin problema (puedo mostrar un Fragmento individual muy bien). Tengo una FragmentActivity en la que quiero mostrar la lista de Fragmentos mencionada anteriormente. Aquí está el código que estoy usando para tratar de poblar el ListView dentro de vista del FragmentActivity:

ArrayList<Fragment> fragList = new ArrayList<Fragment>(); 
    Fragment fragment = Fragment.instantiate(this, TileItem.class.getName()); 
    Bundle bundle = new Bundle(); 
    bundle.putInt("key", 0); 
    fragment.setArguments(bundle); 
    fragList.add(fragment); 

    ArrayAdapter<Fragment> adapter = new ArrayAdapter<Fragment>(this, R.layout.tile_item, fragList); 
    listItems.setAdapter(adapter); 

Aquí está mi modo de pensar en esto. Hago un ArrayList de fragmentos para contener todas mis vistas creadas. Luego creo un Fragmento, creo un Paquete, agrego datos al Paquete (para que el Fragmento pueda reunir datos en sus Vistas correctamente), agrego el Paquete al Fragmento, luego finalmente agrego el Fragmento a la Lista de Arreglos. Después de eso, hago un ArrayAdapter, agrego el diseño del elemento que quiero usar y la lista de Fragmentos que he hecho; luego configure el ListView para leer desde mi adaptador.

Cualquiera que ejecute este código probablemente obtendrá el NPE @ creando una instancia del ArrayAdapter. ¿Lo que da? ¿Esto es posible? Antes de seguir analizando mi cerebro, ¿alguien puede decirme si solo estoy perdiendo el tiempo? ¿Hay una mejor manera? He estado pensando en usar ScrollView, pero gran parte de la funcionalidad de un ListView necesitaría volver a implementarse y odio, odio, odio, reinventar la rueda cuando no es necesario.

Gracias a todos los que lean, y especialmente gracias por su opinión si decide dejarlos. Intenté buscar una respuesta establecida, pero todo lo que parece son preguntas/páginas web sobre el uso de un ListView INSIDE de un fragmento; no usar Fragmentos COMO LOS ELEMENTOS de un ListView

Editar: Tomé las sugerencias a continuación y comencé a investigar más. Por la forma en que aparecen las cosas, debería ser capaz de usar un adaptador personalizado que infla fragmentos en lugar de simplemente construir desde XML (a falta de una mejor manera de describir el proceso). Sin embargo, mi implementación actual arroja un NPE cuando intento establecer el adaptador

Aquí está mi código adaptador personalizado (acortado por razones de brevedad):

public class AdapterItem extends ArrayAdapter<Fragment> { 

Context c; 
List<Fragment> f; 

public AdapterItem(Context c, List<Fragment> f) { 
    super(c, R.layout.tile_item, f); 
    this.c = c; 
    this.f = f; 
} 

@Override 
public View getView(int pos, View v, ViewGroup vg) { 
    LayoutInflater i = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    return i.inflate(R.layout.tile_item, vg, false); 
} 

}

y aquí es cómo estoy implementarlo:

ArrayList<Fragment> fragList = new ArrayList<Fragment>(); 
    Fragment fragment = Fragment.instantiate(this, TileItem.class.getName()); 
    Bundle bundle = new Bundle(); 
    bundle.putInt("key", 0); 
    fragment.setArguments(bundle); 
    fragList.add(fragment); 

    AdapterItem adapter = new AdapterItem(this, fragList); 
    adapter.add(fragment); 
    listItems.setAdapter(adapter); 

así que ha sido unos pocos días y estoy bastante seguro de que este hilo ha sido enterrado. Sin embargo, pensé en agregar una última actualización por si alguien quiere probar esto y una búsqueda en Google los trae aquí. Entonces, en mi implementación obtengo un NPE cuando el ListView recibe el adaptador. No hace falta ser un cirujano espacial para descubrir que ciertamente es el adaptador y no el ListView que arroja el error. Por mi vida, no puedo entender por qué ...

En cualquier caso, creo que tengo una idea. Primero, un poco de historia: hace un tiempo que estaba tratando de hacer FragmentTransactions dentro de un FragmentDialog. Cada vez que intentaba hacerlo, obtenía un NPE. Eventualmente, a través de mucha investigación, descubrí que la razón se relacionaba con la forma en que los Fragmentos son instanciados. Cuando se llama a un Fragmento, necesita el contexto de su padre. Como el elemento primario de Dialog es la actividad que lo inició, el cuadro de diálogo en sí no cumplía los criterios necesarios.Creo que al intentar agregar fragmentos a un ListView, este también es el caso. Como el ListView no cumple con el acuerdo de instaurar un Fragment, lanza el NPE y, por lo tanto, me deja colgando y volviendo a las convenciones. D @ mn ... Realmente había esperado poder hacer esto. Usar Fragmentos en lugar de XML simple habría facilitado mucho la organización/búsqueda a través de la lista. Oh, bueno ... supongo que no se puede hacer en caso de que alguien se esté preguntando.

+2

¿Por qué te * quiere * fragmentos para ser "ELEMENTOS de un ListView"? Los desarrolladores han estado creando 'ListView's durante años sin que sus elementos sean fragmentos. ¿Qué esperas obtener al convertirlos en fragmentos? – CommonsWare

+1

Bueno, espero poder mostrar algo más que un simple TextView dentro de una lista (de hecho, podré mostrar una imagen y algunas líneas de texto adicionales). Además, podré reutilizar el código de fragmento una y otra vez de diferentes actividades sin duplicar el código. También he visto listas de desplazamiento de elementos que son más dinámicos que un simple TextView (como las listas en Google Play, son más complejas que solo un TextView). ¿Cómo se logra eso? ¿No sería posible ese mismo efecto (más fácil) usando un Fragmento? – user1449018

+3

Puede hacerlo utilizando Adaptador y Vistas inflados desde XML para sus filas. –

Respuesta

8

yo diría que esto no es posible hacerlo como poner un fragmento de un ListView que significaría el fragmento se puede multiplicar a través de múltiples recipientes. Cuando utiliza FragmentManager para crear un fragmento, se etiqueta con un identificador, por lo que es sencillo recargar y reorganizar la orientación y otros cambios de configuración. También fomenta el uso en múltiples configuraciones de dispositivos.

Un fragmento es realmente un subconjunto de una actividad. ¿Alguna vez tendrías una actividad como parte de una lista? Definitivamente no (¡debería ser la respuesta!) !!!

Además, no es muy útil para unir() y separar() un fragmento de forma continua a medida que se mueven dentro y fuera de la vista (células se reciclan). Todas estas son operaciones costosas que un ListView no debería tratar. Las listas deben desplazarse rápidamente.

De la conversación en los comentarios, puedo ver que quiere lograr código agradable con una buena separación de código de configuración de la vista y el adaptador en la actividad. Hazlo con cualquiera de los siguientes:

  1. Reemplaza la clase View y haz allí tu dibujo y configuración personalizados.
  2. crear una nueva clase, en la que se proporciona un conjunto contexto y los datos necesarios para que pueda a volver la vista una lista tiene que mostrar - esto es lo que suelo hacer.
  3. Tenga una clase de Utils para construir su video en otra parte (tonto).

simplemente no lo utiliza fragmentos en las listas. No es el caso de uso que están buscando. HTH.

3

No necesita utilizar Fragmentos.

Escriba un ViewAdapter personalizado y hágalo inflar un diseño más complejo (o tal vez varios diseños más complejos si es que necesita ser realmente elegante) y rellene los campos del diseño según sea necesario.

[Aparte: a las personas que respondieron en los comentarios - por favor utilice respuestas en lugar de comentarios si en realidad se está respondiendo a la pregunta! ¡Si solo porque obtiene más puntos de reputación de esa manera!]

+0

PD: Si está intentando reutilizar partes de un diseño en otro, eche un vistazo al elemento

7

Resulta que puede crear un ListView donde cada elemento de la listaView es Fragment. El truco está envolviendo el Fragmento en un FrameLayout.

ACTUALIZACIÓN 9/16/2014

A pesar de que es posible para crear un ListView que contiene Fragments, que no se ve como que es una buena idea. Esto parece ser definitivamente un caso de esquina en el mundo de Android y habrá dragones. Para un fragmento simple como el del siguiente ejemplo, todo funciona muy bien, pero si tiene un proyecto complejo con mucho en juego, probablemente este no sea el camino a seguir. Mi nuevo enfoque es extraer todo el código relacionado con la GUI en un View que se extiende a FrameLayout, e insertarlo en un ListView - esto funciona MUCHO MEJOR y está más en línea con la forma en que Android espera ser utilizado.Si necesita la funcionalidad de un Fragment en otras partes de su código, simplemente puede usar este nuevo View allí también.

Volver a la respuesta original ...

He añadido un nuevo ManyFragments ejemplo a mi AnDevCon 14 Fragments example app si quieres probarlo. En esencia se trata de la del BaseAdapter, que en mi ejemplo es el siguiente:

BaseAdapter adapter = new BaseAdapter() { 
     @Override public int getCount() { return 10000; } 
     @Override public Object getItem(int i) { return new Integer(i); } 
     @Override public long getItemId(int i) { return i; } 

     @Override 
     public View getView(int i, View view, ViewGroup viewGroup) { 

      if (view!=null){ 
       ManyListItemFragment fragment = (ManyListItemFragment) view.getTag(); 
       fragment.setCount(i); 
      } else { 
       FrameLayout layout = new FrameLayout(getActivity()); 
       layout.setLayoutParams(frameLayoutParams); 
       int id = generateViewId(); 
       layout.setId(id); 
       ManyListItemFragment fragment = new ManyListItemFragment(); 
       fragment.setCount(i); 
       getChildFragmentManager() 
         .beginTransaction() 
         .replace(id,fragment) 
         .commit(); 
       view = layout; 
       view.setTag(fragment); 
      } 

      return view; 
     } 
    }; 

En caso de que usted es curioso aquí es generateViewId():

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 
public static int generateViewId() { 
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 
     for (;;) { 
      final int result = sNextGeneratedId.get(); 
      // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 
      int newValue = result + 1; 
      if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 
      if (sNextGeneratedId.compareAndSet(result, newValue)) { 
       return result; 
      } 
     } 
    } else { 
     return View.generateViewId(); 
    } 
} 
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 
+0

¿Puede guiarme cómo se supone que debo crear un diseño diferente para cada lista? ít – Shadow

Cuestiones relacionadas