android - putextra - ¿Puede un ListView contener fragmentos?
send string to fragment android (3)
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.
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 Fragment funcionan sin problemas (puedo mostrar un Fragment 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 llenar el ListView dentro de la Vista de 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 sobre 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 leen, y especialmente gracias por tus pensamientos si decides 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 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 de adaptador personalizado (abreviado para abreviar):
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 así es como lo estoy implementando:
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 han pasado unos 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.
Diría que esto no es posible, ya que poner un fragmento en un ListView significaría que el fragmento se puede multiplicar en varios contenedores. 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 adjuntar () y separar () un fragmento continuamente a medida que se mueven hacia adentro y fuera de la vista (las células se reciclan). Todas estas son operaciones costosas que un ListView no debería tratar. Las listas deben desplazarse rápidamente.
A partir de la conversación sobre los comentarios, puedo ver que desea lograr un buen código con una buena separación de código de configuración de vista y adaptador en la Actividad. Hazlo con cualquiera de los siguientes:
- Anule la clase
View
y haga su dibujo y configuración personalizados allí. - Cree una clase nueva, en la que proporcione un contexto y un conjunto de datos necesarios para que pueda recuperar la vista que una lista debe mostrar: esto es lo que suelo hacer.
- Tenga una clase de Utils para construir su video en otra parte (tonto).
Simplemente no use Fragmentos en las Listas. No es el caso de uso que están buscando. HTH.
No necesita usar Fragmentos.
Escriba un ViewAdapter personalizado y haga que infle un diseño más complejo (o tal vez varios diseños más complejos si es que necesita ser realmente elegante) y complete los campos del diseño según sea necesario.
[Aparte: a las personas que respondieron en los comentarios: por favor, use respuestas en lugar de comentarios si realmente está respondiendo la pregunta. ¡Si solo porque obtienes más puntos de reputación de esa manera!]
Resulta que puede crear un ListView
donde cada elemento de la listaView es un Fragment
. El truco está envolviendo el Fragmento en un FrameLayout
.
ACTUALIZACIÓN 16/9/2014
Aunque es posible crear un ListView
que contenga Fragments
, no parece que sea 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 una View
que extiende FrameLayout
, e insertar eso en una 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 esta nueva View
también.
Volver a la respuesta original ...
He agregado un nuevo ejemplo de ManyFragments
a mi aplicación de ejemplo AnDevCon 14 Fragments si quieres probarlo. Esencialmente se trata de BaseAdapter
, que en mi ejemplo se ve así:
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 tenga curiosidad, aquí está 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);