2011-10-24 2 views
19

Ho abilitato lo scorrimento veloce in un ListView, che ha un headerview non selezionabile. Se si scorre verso il basso l'elenco e si trascina il pollice di scorrimento veloce verso l'alto, l'elenco scorre solo al primo elemento, ma non alla vista dell'intestazione. Trascinando la lista, funziona come previsto.FastScroller scorre solo fino al primo elemento, non alla vista dell'intestazione

Screenshot1: L'area rossa nello screenshot è la vista dell'intestazione.
Screenshot2: Se si trascina il pollice in alto, si ottiene solo il primo elemento e la vista dell'intestazione è ancora sopra.

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> 

Ho creato un progetto demo: https://github.com/mikegr/fastscroll-bug

Perché trascinando il pollice non scorrere indietro verso l'alto?

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

+0

Hai mai scoperto come risolvere questo problema? – clauziere

risposta

12

Questo è un comportamento intenzionale del FastScroller. Quando chiami setAdapter sul tuo ListView, l'adattatore è avvolto in un HeaderViewListAdapter se ci sono delle intestazioni impostate; questo è il motivo per cui è necessario chiamare addHeaderView prima del setAdapter. Poi, nel codice FastScroller, vediamo:

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

Cioè, ottenere un offset e utilizzare l'adattatore sottostante. mListOffset viene quindi utilizzato per impostare la posizione superiore in cui scorrere con lo scroller veloce. Quindi, dove si svolge questo involucro? Fino a, come previsto, ListView.addHeaderView, dove si vede:

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

Quindi stiamo sicuramente cercando intorno al posto giusto. Ora, sembra che il tuo obiettivo è NON avere il comportamento di offset per le intestazioni di lista per il tuo pollice veloce, ma altrimenti avere un elenco normale con intestazione. Per fare ciò, è sufficiente (in base a ciò che abbiamo visto del codice) avere FastScroller.mListOffset = 0. Questo valore è impostato solo su getSectionsFromIndexer, che è chiamato in modo incondizionato in init e condizionatamente in diverse altre funzioni solo quando mListAdapter == null. mListAdapter è nullo se viene chiamato onSectionsChanged, quindi ignoriamo il percorso per ora.

Dopo un sacco di scavo e giocando con vari ganci di riflessione, posso dire che non c'è modo di farlo che sarà anche leggermente compatibile con il futuro. Puoi usare reflection per scambiare HeaderViewListAdapter con uno che si trova sul numero di intestazioni, ecc; ma è piuttosto fragile. Allo stesso modo, è possibile creare una sottoclasse del FastScroller (pacchetto visibile) con uno con il proprio comportamento; ma lo mListOffset viene riferito ampiamente e non attraverso un getter, quindi questo è ancora più brutto del solito. Fondamentalmente, stai andando contro il fatto che il sistema non funzioni nel modo che preferisci.

Esito a chiamare questo un errore, dal momento che è chiaro dal codice che è un comportamento deliberato. Hai considerato di rendere il primo elemento della lista solo un primo elemento speciale (possibilmente utilizzando un custommolto simile a HeaderViewListAdapter se lo si desidera per la contabilità), piuttosto che usare il meccanismo di intestazione?

+0

il più recente "mListOffset" è ora chiamato "mHeaderCount".Sto impostando entrambi a 0 e tutto sembra andare bene. Senza dubbio ogni versione futura potrebbe rompere la cosa. –