Rileva la fine di ScrollView

Ho un'app, che ha un'attività che utilizza uno ScrollView . Devo rilevare quando l'utente arriva alla fine dello ScrollView . Ho fatto qualche googleing e ho trovato questa pagina where è spiegato. Ma, nell'esempio, questi ragazzi estendono ScrollView . Come ho detto, ho bisogno di estendere l'attività.

Quindi, ho detto "ok, cerchiamo di creare una class personalizzata che estende ScrollView , sovrascrivi il metodo onScrollChanged() , individua la fine del rotolo e agisce di conseguenza".

  • "Il componente SDK Platform Tools manca!"
  • Come sfogliare il frammento di backstack
  • Android ottiene la posizione di scorrimento esatta in ListView
  • Visualizzazioni di Android: può controllare la visibilità prima di impostare la visibilità migliorare le performance?
  • Pulisci l'applicazione Android vuota non riesce a creare - 'non è riuscito a trovare la versione di Strumenti di revisione 23.0.0 rc1'
  • Bug specifici del dispositivo Android
  • Ho fatto, ma in questa linea:

     scroll = (ScrollViewExt) findViewById(R.id.scrollView1); 

    lancia un java.lang.ClassCastException . Ho modificato i tag <ScrollView> nel mio XML ma, ovviamente, non funziona. Le mie domande sono: perché, se ScrollViewExt estende ScrollView , mi ScrollViewExt ScrollView ClassCastException ? c'è un modo per rilevare la fine dello scorrimento senza preoccuparsi troppo?

    Grazie a voi.

    EDIT: Come promesso, ecco il pezzo del mio XML che conta:

     <ScrollView android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="match_parent" > <WebView android:id="@+id/textterms" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:textColor="@android:color/black" /> </ScrollView> 

    Ho cambiato da TextView a WebView per essere in grado di giustificare il text all'interno. Quello che voglio get è che il button "Accetta non triggers finché le condizioni del contratto non sono completamente lette". La mia class estesa è chiamata ScrollViewEx t. Se cambio il tag ScrollView per ScrollViewExt lancia un file

     android.view.InflateException: Binary XML file line #44: Error inflating class ScrollViewExt 

    perché non comprende il tag ScrollViewEx . Non credo che abbia una soluzione …

    Grazie per le tue risposte!

  • android.support.v4.widget.SwipeRefreshLayout funziona ma non è visibile
  • Invio di file tramite POST con HttpURLConnection
  • Creazione di vincoli di chiave esterna in ORMLite in SQLite
  • Android - Imposta carta da parati utilizzando l'intenzione di "Imposta carta da parati"
  • android trascinare e rilasciare ImageView onTouchListener
  • leggere file in asset o cartella cruda in Android
  • 8 Solutions collect form web for “Rileva la fine di ScrollView”

    Fatto!

    A parte la soluzione che Alexandre mi ha fornito gentilmente, ho dovuto creare un'interface:

     public interface ScrollViewListener { void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy); } 

    Poi, ho dovuto ignorare il metodo OnScrollChanged da ScrollView nel mio ScrollViewExt:

     public class ScrollViewExt extends ScrollView { private ScrollViewListener scrollViewListener = null; public ScrollViewExt(Context context) { super(context); } public ScrollViewExt(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ScrollViewExt(Context context, AttributeSet attrs) { super(context, attrs); } public void setScrollViewListener(ScrollViewListener scrollViewListener) { this.scrollViewListener = scrollViewListener; } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (scrollViewListener != null) { scrollViewListener.onScrollChanged(this, l, t, oldl, oldt); } } } 

    Ora, come ha detto Alexandre, inserisci il nome del pacchetto nel tag XML (colpa mia), fai la tua class Attività implementare l'interface creata prima e poi metta insieme:

     scroll = (ScrollViewExt) findViewById(R.id.scrollView1); scroll.setScrollViewListener(this); 

    E nel metodo OnScrollChanged, dall'interface …

     @Override public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) { // We take the last son in the scrollview View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1); int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY())); // if diff is zero, then the bottom has been reached if (diff == 0) { // do stuff } } 

    E ha funzionato!

    Grazie mille per il tuo aiuto, Alexandre!

    La risposta di Fustigador è stata ottima, ma ho trovato alcuni dispositivi (come Samsung Galaxy Note V) non possono raggiungere 0, hanno lasciato 2 punti dopo il calcolo. Suggerisco di aggiungere un po 'di buffer come sotto:

     @Override public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) { // We take the last son in the scrollview View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1); int diff = (view.getBottom() - (scrollView.getHeight() + scrollView.getScrollY())); // if diff is zero, then the bottom has been reached if (diff <= 10) { // do stuff } } 

    Ho trovato un modo semplice per rilevare questo:

     scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { if (scrollView != null) { if (scrollView.getChildAt(0).getBottom() <= (scrollView.getHeight() + scrollView.getScrollY())) { //scroll view is at bottom } else { //scroll view is not at bottom } } } }); 
    • Non è necessario personalizzare ScrollView.
    • Scrollview può ospitare solo un figlio diretto, quindi scrollView.getChildAt (0) è giusto.
    • Questa soluzione è giusta anche l'altezza del figlio diretto della vista di scorrimento è match_parent o wrap_content .

    EDIT

    Con il contenuto del tuo XML, posso vedere che utilizzi un ScrollView. Se desideri utilizzare la tua visualizzazione personalizzata, devi scrivere com.your.packagename.ScrollViewExt e potrai utilizzarla nel tuo codice.

     <com.your.packagename.ScrollViewExt android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="match_parent" > <WebView android:id="@+id/textterms" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:textColor="@android:color/black" /> </com.your.packagename.ScrollViewExt> 

    EDIT END

    Puoi submit il contenuto xml?

    Penso che si potrebbe semplicemente aggiungere un ascoltatore di scorrimento e verificare se l'ultimo elemento mostrato è quello più recente dalla list come:

     mListView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub if(view.getLastVisiblePosition()==(totalItemCount-1)){ //dosomething } } }); 

    È ansible utilizzare il NestedScrollView della libreria di NestedScrollView e l'interface NestedScrollView.OnScrollChangeListener .

    https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html

    In alternativa, se la tua applicazione sta targeting API 23 o superiore, puoi utilizzare il seguente metodo sullo ScrollView :

     View.setOnScrollChangeListener(OnScrollChangeListener listener) 

    Poi seguire l'esempio che @Fustigador descrive nella sua risposta. Si noti comunque che, come descritto, si dovrebbe considerare l'aggiunta di un piccolo buffer nel caso in cui l'utente o il sistema non siano in grado di raggiungere il fondo completo dell'elenco per qualsiasi motivo.

    Vale anche la pena di notare che l'ascoltatore del cambiamento di scorrimento a volte viene chiamato con valori negativi o valori maggiori rispetto all'altezza di visualizzazione. Presumibilmente questi valori rappresentano il "momento" dell'azione di scorrimento. Tuttavia, a less che non siano gestiti in modo appropriato (pavimento / abs), possono causare problemi di rilevazione della direzione di scorrimento quando la vista viene scorsa verso l'alto o il basso della gamma.

    https://developer.android.com/reference/android/view/View.html#setOnScrollChangeListener(android.view.View.OnScrollChangeListener)

    Dovremmo sempre aggiungere scrollView.getPaddingBottom() per adattarsi alla piena altezza di scorrimento visto che una visione di scorrimento temporale ha un riempimento nel file xml in modo che il suo caso non funziona.

     scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() { @Override public void onScrollChanged() { if (scrollView != null) { View view = scrollView.getChildAt(scrollView.getChildCount()-1); int diff = (view.getBottom()+scrollView.getPaddingBottom()-(scrollView.getHeight()+scrollView.getScrollY())); // if diff is zero, then the bottom has been reached if (diff == 0) { // do stuff } } } }); 

    Per determinare se sei alla fine del tuo ScrollView personalizzato, puoi anche utilizzare una variabile membro e memorizzare l'ultima posizione y. Quindi è ansible confrontare l'ultima posizione y con la posizione di scorrimento corrente.

     private int scrollViewPos; ... @Override public void onScrollChanged(ScrollViewExt scrollView, int x, int y, int oldx, int oldy) { //reached end of scrollview if (y > 0 && scrollViewPos == y){ //do something } scrollViewPos = y; } 

    La maggior parte delle risposte funziona accanto a un fatto che quando u scorri verso il basso, a volte il codice è chiamato più volte , che nel mio caso è indesiderabile . Per evitare questo comportmento ho aggiunto flag scrollPositionChanged che controlla se la posizione di scorrimento è cambiata anche prima di call ancora una volta.

     public class EndDetectingScrollView extends ScrollView { private boolean scrollPositionChanged = true; private ScrollEndingListener scrollEndingListener; public interface ScrollEndingListener { void onScrolledToEnd(); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); View view = this.getChildAt(this.getChildCount() - 1); int diff = (view.getBottom() - (this.getHeight() + this.getScrollY())); if (diff <= 0) { if (scrollPositionChanged) { scrollPositionChanged = false; if (scrollEndingListener != null) { scrollEndingListener.onScrolledToEnd(); } } } else { scrollPositionChanged = true; } } public void setScrollEndingListener(ScrollEndingListener scrollEndingListener) { this.scrollEndingListener = scrollEndingListener; } } 

    Poi metti solo l'ascoltatore

     scrollView.setScrollEndingListener(new EndDetectingScrollView.ScrollEndingListener() { @Override public void onScrolledToEnd() { //do your stuff here } }); 

    Puoi fare la stessa cosa se u fai come

     scrollView.getViewTreeObserver().addOnScrollChangedListener(...) 

    ma devi fornire la bandiera dalla tua class aggiungendo questo ascoltatore.

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.