2011-10-24 16 views
19

He habilitado el desplazamiento rápido en un ListView, que tiene una vista de encabezado no seleccionable. Si se desplaza hacia abajo en la lista y arrastra el dedo rápido hacia la parte superior, la lista solo se desplaza al primer elemento, pero no a la vista del encabezado. Arrastrando la lista, funciona como se esperaba.FastScroller solo se desplaza al primer elemento, no a la vista de encabezado

Captura de pantalla1: el área roja en la captura de pantalla es la vista de encabezado.
Captura de pantalla2: si arrastra el pulgar a la parte superior, solo obtendrá el primer elemento y la vista de encabezado aún estará arriba.

ListView lv = (ListView) findViewById(R.id.listView); 
lv.addHeaderView(getLayoutInflater().inflate(R.layout.view,null), null, false); 

 

<ListView 
    android:layout_height="fill_parent" 
    android:id="@+id/listView" 
    android:layout_width="fill_parent" 
    android:fastScrollEnabled="true" 
></ListView> 

He creado un proyecto de demostración: https://github.com/mikegr/fastscroll-bug

¿Por qué arrastrando el dedo pulgar no desplazarse de nuevo a la cima?

Red area is a header view dragging thumb does not go back to top

+0

¿Alguna vez descubrió cómo solucionar este problema? – clauziere

Respuesta

12

Este es un comportamiento deliberado de la FastScroller. Cuando llame al setAdapter en su ListView, el adaptador se envuelve en un HeaderViewListAdapter si hay un conjunto de encabezados; Es por eso que debe llamar al addHeaderView antes del setAdapter. Luego, en el código FastScroller, vemos:

if (adapter instanceof HeaderViewListAdapter) { 
     mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount(); 
     adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); 
    } 

Es decir, obtener una compensación y utilizar el adaptador subyacente. mListOffset se usa para establecer la posición superior para desplazarse a la barra de desplazamiento rápida. Entonces, ¿dónde sucede realmente este envoltorio? Hasta, como se esperaba, ListView.addHeaderView, en el que vemos:

if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { 
     mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); 
    } else { 
     mAdapter = adapter; 
    } 

Así que definitivamente estamos buscando en el lugar correcto. Ahora, parece que su objetivo es NO tener el comportamiento de desplazamiento para encabezados de lista para su pulgar rápido, pero de lo contrario tener una lista normal con encabezado. Para hacer esto, es suficiente (basado en lo que hemos visto del código) tener FastScroller.mListOffset = 0. Esto se establece solo en getSectionsFromIndexer, que se llama incondicionalmente en init, y de forma condicional en otras funciones solo cuando mListAdapter == null. mListAdapter solo es nulo si se llama a onSectionsChanged, entonces ignoremos esa ruta por el momento.

Después de cavar un montón y jugar con varios ganchos de reflexión, puedo decir que no hay forma de hacer esto que sea levemente compatible con el futuro. Puede usar el reflejo para cambiar el HeaderViewListAdapter por uno que mienta sobre su conteo de encabezado, etc .; pero eso es bastante frágil. Del mismo modo, puede subclase el FastScroller (paquete visible) con uno con su propio comportamiento; pero mListOffset se hace referencia ampliamente y no a través de un getter, por lo que esto es incluso más feo que de costumbre. Básicamente, te encuentras con el hecho de que el sistema no funciona del modo que deseas.

Dudo en llamar esto un error, ya que es tan claro en el código que es un comportamiento deliberado. ¿Ha considerado hacer que el primer elemento de la lista sea solo un primer elemento especial (posiblemente usando un WrapperListAdapter personalizado como HeaderViewListAdapter si lo desea para la contabilidad), en lugar de usar el mecanismo de encabezado?

+0

el "mListOffset" más nuevo ahora se llama "mHeaderCount".Estoy configurando ambos en 0 y todo parece estar bien. Sin duda, cada lanzamiento futuro podría romper la cosa. –

Cuestiones relacionadas