Android: acceda a las vistas de los niños desde un ListView

108

Necesito averiguar la posición de píxel de un elemento en una lista que se ha mostrado usando un ListView. Parece que debería obtener uno de TextView y luego usarlo getTop(), pero no puedo averiguar cómo obtener una vista secundaria de un archivoListView .

Actualización: los elementos secundarios de ViewGroupno se corresponden 1 a 1 con los elementos de la lista, para a ListView. En cambio, los elementos ViewGroupsecundarios de 'corresponden solo a las vistas que son visibles en este momento. Entonces getChildAt()opera en un índice que es interno al ViewGroupy no necesariamente tiene nada que ver con la posición en la lista que ListViewusa.

laca
fuente

Respuestas:

215

Ver: Android ListView: obtenga el índice de datos del elemento visible y combínelo con parte de la respuesta de Feet anterior, puede darle algo como:

int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
  Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
  return;
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
View wantedView = listView.getChildAt(wantedChild);

El beneficio es que no está iterando sobre los hijos de ListView, lo que podría sufrir un impacto en el rendimiento.

Joe
fuente
10
Excelente respuesta, pero no funciona bien cuando tiene vistas de encabezado en su lista. La tarea a firstPositiondebería ser int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();arreglar esto.
pospi
@pospi: gracias, buen punto! He actualizado mi respuesta para dar cuenta de eso.
Joe
Buena respuesta y funciona en la mayoría de los casos, pero no entiendo por qué cree que las vistas secundarias aparecen en el orden en que están en la matriz de vistas secundarias. Dado que las vistas se pueden reutilizar, ¿cómo podemos estar seguros de que la primera vista no representa la última vista visible?
Victor Denisov
2
@VictorDenisov: esto solo puede suceder en el hilo de la interfaz de usuario; por lo tanto, el hilo de la interfaz de usuario se bloqueará mientras se ejecuta este código, por lo que las vistas secundarias están estacionarias y no se modificarán. ListViewya está manejando "mover" las vistas secundarias después de reciclar convertViews antiguas , etc., por lo que puede estar seguro de que ListView.getChildAt(0) es la primera vista adjunta desde el adaptador. Es posible que no sea completamente visible (y es posible que ni siquiera sea visible en absoluto, según el ListViewumbral de "visibilidad" antes de reciclar una vista que se considera "desplazada fuera de la vista")
Joe
1
@Matheus no es así como funciona Android ListView. Si el elemento de la lista está fuera de la pantalla, su vista ya se ha reciclado y reutilizado para uno de los otros elementos de la lista que están en la pantalla. Debería volver a pensar cómo está usando ListView si ese es un requisito.
Joe
17

Este código es más fácil de usar:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if(rowView != null)
        {
           // Your code here
        }
Kalimah
fuente
9
no siempre funciona. getChildAt cuenta desde la primera fila visible, no desde la parte superior de los datos.
SteelBytes
13
El argumento ViewID es confuso. Es un índice (o posición). El ID de vista es un entero completamente arbitrario generado por la herramienta aapt.
Johan Pelgrim
6

Una búsqueda rápida de los documentos de la clase ListView ha arrojado los métodos getChildCount () y getChildAt () heredados de ViewGroup. ¿Puedes recorrerlos usando estos? No estoy seguro, pero vale la pena intentarlo.

Lo encontré aquí

Pies
fuente
1
He intentado esto, para hacer selecciones. Por lo general, funciona, pero a veces hay errores uno por uno y no es confiable. Yo no lo recomendaría.
Timmmm
Gracias Timmmm, en realidad no lo había probado, solo lo encontré en los documentos.
Pies
5
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
        View v;
        int count = parent.getChildCount();
        v = parent.getChildAt(position);
        parent.requestChildFocus(v, view);
        v.setBackground(res.getDrawable(R.drawable.transparent_button));
        for (int i = 0; i < count; i++) {
            if (i != position) {
                v = parent.getChildAt(i);
                v.setBackground(res.getDrawable(R.drawable.not_clicked));
            }
        }
    }
});

Básicamente, crea dos Dibujables : uno transparente y otro del color deseado. Solicite el enfoque en la posición en la que se hizo clic ( int positioncomo se define) y cambie el color de dicha fila. Luego, revise el padre ListViewy cambie todas las demás filas en consecuencia. Esto tiene en cuenta cuando un usuario hace clic en listviewvarias veces. Esto se hace con un diseño personalizado para cada fila de la ListView. (Muy simple, simplemente cree un nuevo archivo de diseño con un TextView- ¡no establezca que se pueda enfocar o hacer clic!).

No se requiere adaptador personalizado - usar ArrayAdapter

Wes
fuente
getChildAt es relativo a los elementos desplazados actuales. Esto dejará de funcionar si se desplaza un poco por la lista.
nurettin
4
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);
Milaaaad
fuente
1
Elaborar un poco
innoSPG
-9

Esto supone que conoce la posición del elemento en ListView:

  View element = listView.getListAdapter().getView(position, null, null);

Entonces debería poder llamar a getLeft () y getTop () para determinar los elementos en la posición de la pantalla.

Jasonhudgins
fuente
43
getView()es llamado internamente por ListView, al completar la lista. No debe usarlo para obtener la vista en esa posición en la lista, ya que llamar getView()con null para convertViewhace que el adaptador infle una nueva vista desde el recurso de diseño del adaptador (no obtiene la vista que ya se está mostrando).
Joe
1
La posición uniforme será una posición en la pantalla visual, no en la posición de la fuente de datos del adaptador.
Vikas
@jasonhudgins Este es el método que he estado usando porque pensé que es el mejor, pero cuando trato de hacer invisible una barra de progreso en la vista secundaria, en cambio, hizo que todas las barras de progreso en listvew fueran invisibles ... todo en toda la respuesta aceptada hizo el truco
Edijae Crusar