Android: rileva quando ScrollView smette di scorrere


87

Sto usando un ScrollViewin Android e dove la parte visibile di ha ScrollViewle stesse dimensioni di una delle celle all'interno di Scrollview. Ogni "cella" ha la stessa altezza. Quindi quello che sto cercando di fare è scattare in posizione dopo che ScrollViewè stato fatto scorrere.

Attualmente sto rilevando quando l'utente ha toccato ScrollViewe quando ha iniziato a scorrere e lavorare da lì, ma è abbastanza bacato. Deve anche funzionare quando l'utente lo sfiora e scorre e poi decelera.

Su iPhone c'è una funzione che è qualcosa di simile didDeceleratee lì posso fare qualsiasi codice voglio quando ScrollViewha finito di scorrere. C'è una cosa del genere con Android? O c'è del codice che potrei esaminare per trovare un modo migliore per farlo?

Ho esaminato i documenti Android e non sono riuscito a trovare nulla di simile.

Risposte:


102

Di recente ho dovuto implementare la funzione che hai descritto. Quello che ho fatto è stato quello di avere un Runnable che controlla se ScrollView aveva smesso di scorrere confrontando il valore restituito da getScrollY () quando onTouchEvent viene attivato per la prima volta con il valore restituito dopo un tempo definito dalla variabile newCheck .

Vedere il codice di seguito (soluzione funzionante):

public class MyScrollView extends ScrollView{

private Runnable scrollerTask;
private int initialPosition;

private int newCheck = 100;
private static final String TAG = "MyScrollView";

public interface OnScrollStoppedListener{
    void onScrollStopped();
}

private OnScrollStoppedListener onScrollStoppedListener;

public MyScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);

    scrollerTask = new Runnable() {

        public void run() {

            int newPosition = getScrollY();
            if(initialPosition - newPosition == 0){//has stopped

                if(onScrollStoppedListener!=null){

                    onScrollStoppedListener.onScrollStopped();
                }
            }else{
                initialPosition = getScrollY();
                MyScrollView.this.postDelayed(scrollerTask, newCheck);
            }
        }
    };
}

public void setOnScrollStoppedListener(MyScrollView.OnScrollStoppedListener listener){
    onScrollStoppedListener = listener;
}

public void startScrollerTask(){

    initialPosition = getScrollY();
    MyScrollView.this.postDelayed(scrollerTask, newCheck);
}

}

Dopo io ho:

scroll.setOnTouchListener(new OnTouchListener() {

        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_UP) {

                scroll.startScrollerTask();
            }

            return false;
        }
});
scroll.setOnScrollStoppedListener(new OnScrollStoppedListener() {

        public void onScrollStopped() {

            Log.i(TAG, "stopped");

        }
});

A proposito, ho usato poche idee da altre risposte per farlo nella mia app. Spero che sia di aiuto. Qualsiasi domanda non esitate a chiedere. Saluti.


11
Grazie, cerco da anni qualcosa di simile. Utilizzato invece per HorizontalScrollView, che (ovviamente) funziona anche. Solo getScrollY () deve essere sostituito da getScrollX ()
Schnodahipfe

2
Li ho provati tutti qui. Questo è l'UNICO che funziona.
Mike6679

23

Ecco un'altra correzione al bug dell'evento OnEndScroll mancante, IMHO, in ScrollView.

È ispirato da una risposta ambiziosa . Trascina semplicemente questa classe nel tuo progetto (modifica il pacchetto in modo che corrisponda al tuo) e usa l'xml sottostante

package com.thecrag.components.ui;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

public class ResponsiveScrollView extends ScrollView {

    public interface OnEndScrollListener {
        public void onEndScroll();
    }

    private boolean mIsFling;
    private OnEndScrollListener mOnEndScrollListener;

    public ResponsiveScrollView(Context context) {
        this(context, null, 0);
    }

    public ResponsiveScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ResponsiveScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void fling(int velocityY) {
        super.fling(velocityY);
        mIsFling = true;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldX, int oldY) {
        super.onScrollChanged(x, y, oldX, oldY);
        if (mIsFling) {
            if (Math.abs(y - oldY) < 2 || y >= getMeasuredHeight() || y == 0) {
                if (mOnEndScrollListener != null) {
                    mOnEndScrollListener.onEndScroll();
                }
                mIsFling = false;
            }
        }
    }

    public OnEndScrollListener getOnEndScrollListener() {
        return mOnEndScrollListener;
    }

    public void setOnEndScrollListener(OnEndScrollListener mOnEndScrollListener) {
        this.mOnEndScrollListener = mOnEndScrollListener;
    }

}

cambiando di nuovo il nome del pacchetto in modo che corrisponda al progetto

<com.thecrag.components.ui.ResponsiveScrollView
        android:id="@+id/welcome_scroller"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/welcome_scroll_command_help_container"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/welcome_header_text_thecrag"
        android:layout_margin="6dp">
    ....
</com.thecrag.components.ui.ResponsiveScrollView>

2
+1 Risposta simpatica e semplice. A cambiare il valore di differenza 2per 0.5fin modo da riflettere l'originale ScrollView's MAX_SCROLL_FACTORvalore.
Phil

2
Questa implementazione è buona ma non è riuscita quando la visualizzazione a scorrimento non è piena all'inizio. Ecco una soluzione alternativa (per una visualizzazione a scorrimento orizzontale, quindi sostituisci tutte le x con y per ottenerne una verticale): @Override protected void onScrollChanged (int x, int y, int oldX, int oldY) {super.onScrollChanged (x, y , oldX, oldY); if (Math.abs (x - oldX) <SCROLL_FINISHED_THRESHOLD && x! = lastStopX || x> = getMeasuredWidth () || x == 0) {lastStopX = x; if (mOnEndScrollListener! = null) {mOnEndScrollListener.onScrollEnded (); }}}
Snicolas

Questo non funziona sempre. Come nell'emulatore, public void fling (int velocityY) non viene sempre chiamato. La soglia di fine scorrimento a volte è superiore a 20 px.
Andrew Feng

9

Ho sottoclasse (orizzontale) ScrollView e ho fatto qualcosa del genere:

@Override
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
    if (Math.abs(x - oldX) > SlowDownThreshold) {  
        currentlyScrolling = true;
    } else {
        currentlyScrolling = false;
        if (!currentlyTouching) {
            //scrolling stopped...handle here
        }
    }
    super.onScrollChanged(x, y, oldX, oldY);
}

Ho usato un valore di 1 per SlowDownThreshold poiché sembra sempre essere la differenza dell'ultimo evento onScrollChanged.

Affinché questo si comporti correttamente durante il trascinamento lento, ho dovuto fare questo:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            currentlyTouching = true;
    }
    return super.onInterceptTouchEvent(event);
}

@Override
public boolean onTouch(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            currentlyTouching = false;
            if (!currentlyScrolling) {
                //I handle the release from a drag here
                return true;
            }
    }
    return false;
}

Bella risposta. L'unica aggiunta. In onInterceptTouchEvent () hai anche gestire MotionEvent.ACTION_UP e MotionEvent.ACTION_CANCEL altrimenti currentlyTouching rimarrà vero nel caso in cui apri un'altra attività sul clic.
Cynichniy Bandera

Un'altra correzione: in onScrollChanged () devi anche controllare la fine dello scorrimento anche se il rallentamento non è ancora 1. In questo modo: boolean end = (oldx> x)? (x <= 0): (x> = getMaxScrollAmount ()); if (Math.abs (x - oldx)> 1 &&! end) {scroll start; } else {scroll end}
Cynichniy Bandera

Questo non funziona su alcuni dispositivi, ad esempio GS3. Sul mio GS3, la differenza tra y e old y PU essere 1 durante la metà dello scorrimento. Tuttavia, funziona perfettamente sul mio Nexus 4. Non sono sicuro del perché.
Bryan,

Non funziona nemmeno su Samsung Galaxy Note 2 e Asus Memo Pad 7. Vedo anche incrementi di 1 al centro dello scorrimento su questi dispositivi.
Oliver Hausler

7

Il mio approccio è determinare lo stato di scorrimento in base a un timestamp modificato ogni volta che viene chiamato onScrollChanged (). È molto facile determinare l'inizio e la fine dello scorrimento. Puoi anche cambiare la soglia (io uso 100 ms) per correggere la sensibilità.

public class CustomScrollView extends ScrollView {
    private long lastScrollUpdate = -1;

    private class ScrollStateHandler implements Runnable {

        @Override
        public void run() {
            long currentTime = System.currentTimeMillis();
            if ((currentTime - lastScrollUpdate) > 100) {
                lastScrollUpdate = -1;
                onScrollEnd();
            } else {
                postDelayed(this, 100);
            }
        }
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (lastScrollUpdate == -1) {
            onScrollStart();
            postDelayed(new ScrollStateHandler(), 100);
        }

        lastScrollUpdate = System.currentTimeMillis();
    }

    private void onScrollStart() {
        // do something
    }

    private void onScrollEnd() {
        // do something
    }

}

Ottima soluzione. Funziona come previsto.
Oliver Hausler

Grazie per il tuo codice. Come rilevare il metodo listener di inizio scorrimento dal codice. si prega di guardare la mia domanda stackoverflow.com/questions/27864700/...
MAMurali

7

Ecco un'altra soluzione, abbastanza semplice e pulita a mio avviso, naturalmente ispirata alle risposte sopra. Fondamentalmente una volta che l'utente ha terminato il gesto, controlla se getScrollY () sta ancora cambiando, dopo un breve ritardo (qui 50 ms).

public class ScrollViewWithOnStopListener extends ScrollView {

    OnScrollStopListener listener;

    public interface OnScrollStopListener {
        void onScrollStopped(int y);
    }

    public ScrollViewWithOnStopListener(Context context) {
        super(context);
    }

    public ScrollViewWithOnStopListener(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                checkIfScrollStopped();
        }

        return super.onTouchEvent(ev);
    }

    int initialY = 0;

    private void checkIfScrollStopped() {
        initialY = getScrollY();
        this.postDelayed(new Runnable() {
            @Override
            public void run() {
                int updatedY = getScrollY();
                if (updatedY == initialY) {
                    //we've stopped
                    if (listener != null) {
                        listener.onScrollStopped(getScrollY());
                    }
                } else {
                    initialY = updatedY;
                    checkIfScrollStopped();
                }
            }
        }, 50);
    }

    public void setOnScrollStoppedListener(OnScrollStopListener yListener) {
        listener = yListener;
    }
}

5

Il mio approccio per questa domanda consiste nell'usare un timer per verificare i seguenti 2 "eventi".

1) onScrollChanged () ha smesso di essere chiamato

2) Il dito dell'utente si solleva dalla scrollview

public class CustomScrollView extends HorizontalScrollView {

public CustomScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

Timer ntimer = new Timer();
MotionEvent event;

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) 
{
    checkAgain();
    super.onScrollChanged(l, t, oldl, oldt);
}

public void checkAgain(){
    try{
        ntimer.cancel();
        ntimer.purge();
    }
    catch(Exception e){}
    ntimer = new Timer();
    ntimer.schedule(new TimerTask() {

        @Override
        public void run() {

            if(event.getAction() == MotionEvent.ACTION_UP){
                // ScrollView Stopped Scrolling and Finger is not on the ScrollView
            }
            else{
                // ScrollView Stopped Scrolling But Finger is still on the ScrollView
                checkAgain();
            }
        }
    },100);

}

@Override
public boolean onTouchEvent(MotionEvent event) {
    this.event = event; 
    return super.onTouchEvent(event);
    }
}

3

Per un caso semplice come quello descritto, probabilmente puoi farla franca ignorando il metodo di lancio nella tua visualizzazione a scorrimento personalizzata. Il metodo Fling viene chiamato per eseguire la "decelerazione" ogni volta che l'utente alza il dito dallo schermo.

Quindi quello che dovresti fare è qualcosa del genere:

  1. Sottoclasse ScrollView.

    public class MyScrollView extends ScrollView { 
    
        private Scroller scroller;  
        private Runnable scrollerTask; 
    
        //...
    
        public MyScrollView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            scroller = new Scroller(getContext()); //or OverScroller for 3.0+
            scrollerTask = new Runnable() {
                @Override
                public void run() {
                    scroller.computeScrollOffset();
                    scrollTo(0, scroller.getCurrY());
    
                    if (!scroller.isFinished()) {
                        MyScrollView.this.post(this);
                    } else {
                        //deceleration ends here, do your code
                    }
                }
            };
            //...
        }
    }
    
  2. Metodo di lancio delle sottoclassi e NON chiamare l'implementazione della superclasse.

    @Override  
    public void fling(int velocityY) {  
        scroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0, container.getHeight());
        post(scrollerTask);  
    
        //add any extra functions you need from android source code:
        //show scroll bars
        //change focus
        //etc.
    }
    
  3. Fling non si attiverà se l'utente smette di scorrere prima di alzare il dito (velocityY == 0). Nel caso in cui desideri intercettare anche questo tipo di eventi, sovrascrivi onTouchEvent.

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean eventConsumed = super.onTouchEvent(ev);
        if (eventConsumed && ev.getAction() == MotionEvent.ACTION_UP) {
            if (scroller.isFinished()) {
                //do your code
            }
        }
        return eventConsumed;
    }
    

NOTA Sebbene funzioni, ignorare il metodo di lancio potrebbe essere una cattiva idea. È pubblico, ma è progettato a malapena per la sottoclasse. In questo momento fa 3 cose: avvia fling per mScroller privato, gestisce possibili cambiamenti di focus e mostra le barre di scorrimento. Questo potrebbe cambiare nella futura versione di Android. Ad esempio, l'istanza mScroller privata ha cambiato la sua classe da Scroller a OvershootScroller tra 2.3 e 3.0. Devi tenere a mente tutte queste piccole differenze. In ogni caso, sii pronto per conseguenze impreviste in futuro.


Cos'è container.getHeight () nel secondo passaggio (2.)?
Mitul Varmora

1
container è la vista che si trova all'interno di scrollView. Poiché scrollView può contenere solo 1 figlio, puoi sostituire container con getChildAt (0).
Alexey

3

La mia soluzione è una variazione dell'ottima soluzione di Lin Yu Cheng e rileva anche quando lo scorrimento è iniziato e interrotto.

Passaggio 1. Definire un HorizontalScrollView e OnScrollChangedListener:

CustomHorizontalScrollView scrollView = (CustomHorizontalScrollView) findViewById(R.id.horizontalScrollView);

horizontalScrollListener = new CustomHorizontalScrollView.OnScrollChangedListener() {
    @Override
    public void onScrollStart() {
        // Scrolling has started. Insert your code here...
    }

    @Override
    public void onScrollEnd() {
         // Scrolling has stopped. Insert your code here...
    }
};

scrollView.setOnScrollChangedListener(horizontalScrollListener);

Passaggio 2. Aggiungere la classe CustomHorizontalScrollView:

public class CustomHorizontalScrollView extends HorizontalScrollView {
    public interface OnScrollChangedListener {
        // Developer must implement these methods.
        void onScrollStart();
        void onScrollEnd();
    }

    private long lastScrollUpdate = -1;
    private int scrollTaskInterval = 100;
    private Runnable mScrollingRunnable;
    public OnScrollChangedListener mOnScrollListener;

    public CustomHorizontalScrollView(Context context) {
        this(context, null, 0);
        init(context);
    }

    public CustomHorizontalScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        init(context);
    }

    public CustomHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        // Check for scrolling every scrollTaskInterval milliseconds
        mScrollingRunnable = new Runnable() {
            public void run() {
                if ((System.currentTimeMillis() - lastScrollUpdate) > scrollTaskInterval) {
                    // Scrolling has stopped.
                    lastScrollUpdate = -1;
                    //CustomHorizontalScrollView.this.onScrollEnd();
                    mOnScrollListener.onScrollEnd();
                } else {
                    // Still scrolling - Check again in scrollTaskInterval milliseconds...
                    postDelayed(this, scrollTaskInterval);
                }
            }
        };
    }

    public void setOnScrollChangedListener(OnScrollChangedListener onScrollChangedListener) {
        this.mOnScrollListener = onScrollChangedListener;
    }

    public void setScrollTaskInterval(int scrollTaskInterval) {
        this.scrollTaskInterval = scrollTaskInterval;
    }

    //void onScrollStart() {
    //    System.out.println("Scroll started...");
    //}

    //void onScrollEnd() {
    //    System.out.println("Scroll ended...");
    //}

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mOnScrollListener != null) {
            if (lastScrollUpdate == -1) {
                //CustomHorizontalScrollView.this.onScrollStart();
                mOnScrollListener.onScrollStart();
                postDelayed(mScrollingRunnable, scrollTaskInterval);
            }

            lastScrollUpdate = System.currentTimeMillis();
        }
    }
}

2

Prova a dare un'occhiata a questa domanda qui su StackOverflow: non è esattamente la stessa della tua domanda, ma dà un'idea di come puoi gestire l'evento di scorrimento di unScrollView .

Fondamentalmente è necessario crearne uno personalizzato CustomScrollViewestendendolo ScrollViewe sostituendolo onScrollChanged(int x, int y, int oldx, int oldy). Quindi devi fare riferimento a questo nel tuo file di layout invece dello standard ScrollViewcome com.mypackage.CustomScrollView.


Questo onScrollChanged () è effettivamente quello che sto usando al momento. Grazie comunque.
user1053691

2

Ci sono alcune ottime risposte qui, ma il mio codice può rilevare quando lo scorrimento si interrompe senza dover estendere la classe ScrollView. ogni istanza di visualizzazione può chiamare getViewTreeObserver (). quando si tiene questa istanza di ViewTreeObserver è possibile aggiungere un OnScrollChangedListener utilizzando la funzione addOnScrollChangedListener ().

dichiarare quanto segue:

private ScrollView scrollListener;
private volatile long milesec;

private Handler scrollStopDetector;
private Thread scrollcalled = new Thread() {

    @Override
    public void run() { 
        if (System.currentTimeMillis() - milesec > 200) {
            //scroll stopped - put your code here
        }
    }
}; 

e nel tuo onCreate (o in un altro luogo) aggiungi:

    scrollListener = (ScrollView) findViewById(R.id.scroll);

    scrollListener.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {

        @Override
        public void onScrollChanged() {
            milesec = System.currentTimeMillis();
            scrollStopDetector.postDelayed(scrollcalled, 200);
        }
    });

potresti volerci più o meno tempo tra questi controlli, ma quando scorri questo listner viene chiamato molto velocemente, quindi funzionerà molto velocemente.


Non ho provato in questo caso, ma dalla mia esperienza immagino che la chiamata ripetitiva e reciproca di postDelayed da onScrollChanged causerà perdite di memoria.
Oliver Hausler

2

Ecco la mia soluzione che include il monitoraggio dello scorrimento e la fine dello scorrimento:

public class ObservableHorizontalScrollView extends HorizontalScrollView {
    public interface OnScrollListener {
        public void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY);
        public void onEndScroll(ObservableHorizontalScrollView scrollView);
    }

    private boolean mIsScrolling;
    private boolean mIsTouching;
    private Runnable mScrollingRunnable;
    private OnScrollListener mOnScrollListener;

    public ObservableHorizontalScrollView(Context context) {
        this(context, null, 0);
    }

    public ObservableHorizontalScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();

        if (action == MotionEvent.ACTION_MOVE) {
            mIsTouching = true;
            mIsScrolling = true;
        } else if (action == MotionEvent.ACTION_UP) {
            if (mIsTouching && !mIsScrolling) {
                if (mOnScrollListener != null) {
                    mOnScrollListener.onEndScroll(this);
                }
            }

            mIsTouching = false;
        }

        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldX, int oldY) {
        super.onScrollChanged(x, y, oldX, oldY);

        if (Math.abs(oldX - x) > 0) {
            if (mScrollingRunnable != null) {
                removeCallbacks(mScrollingRunnable);
            }

            mScrollingRunnable = new Runnable() {
                public void run() {
                    if (mIsScrolling && !mIsTouching) {
                        if (mOnScrollListener != null) {
                            mOnScrollListener.onEndScroll(ObservableHorizontalScrollView.this);
                        }
                    }

                    mIsScrolling = false;
                    mScrollingRunnable = null;
                }
            };

            postDelayed(mScrollingRunnable, 200);
        }

        if (mOnScrollListener != null) {
            mOnScrollListener.onScrollChanged(this, x, y, oldX, oldY);
        }
    }

    public OnScrollListener getOnScrollListener() {
        return mOnScrollListener;
    }

    public void setOnScrollListener(OnScrollListener mOnEndScrollListener) {
        this.mOnScrollListener = mOnEndScrollListener;
    }

}

2

Penso che questo sia successo in passato. AFAIK, non puoi rilevarlo facilmente . Il mio suggerimento è di dare un'occhiata a ScrollView.java(è così che facciamo le cose in Android Land :)) e capire come estendere la classe per fornire la funzionalità che stai cercando. Questo è quello che proverei prima:

 @Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
     if (mScroller.isFinished()) {
         // do something, for example call a listener
     }
 }

Bello, non ho notato il metodo isFinished!
Jordi Coscolla

3
Grazie. Come si accede a questo metodo isFinished ()? Ho dato un'occhiata al file ScrollView.java e mScroller è privato e non posso dire in alcun modo per accedervi.
user1053691

Hmm, davvero. Non ho guardato abbastanza da vicino. Ecco perché ho detto che avrei provato prima :). Si potrebbe fare altre cose, come monitorare le chiamate a onScrollChanged, scrollToo qualsiasi altro metodo di scorrimento-correlato. In alternativa, puoi semplicemente copiare l'intero ScrollViewcodice e creare quel campo protected. Non lo consiglierei, però.
Felix

1
Accesso a mScroller tramite la riflessione. Anche se non funziona, isFinished () viene attivato ogni volta che lo scrollview raggiunge la posizione del dito, il che è quasi continuo L'evento di arresto dello scorrimento dovrebbe attivarsi quando entrambi gli utenti rilasciano il dito e lo scroller smette di scorrere.
amik

20
Questa risposta sembrava davvero promettente, ma dal momento che è un po 'morta, forse dovrebbe essere rimossa?
spaaarky

2

questo è un vecchio thread ma vorrei aggiungere una soluzione più breve che ho trovato:

 buttonsScrollView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->

            handler.removeCallbacksAndMessages(null)

            handler.postDelayed({
                  //YOUR CODE TO BE EXECUTED HERE
                },1000)
        }

Naturalmente c'è un ritardo di 1000 millisecondi. Aggiustalo se necessario.


1

Ho apportato alcuni miglioramenti alla risposta di ZeroG. Principalmente l'annullamento delle chiamate di attività in eccesso e l'implementazione dell'intera operazione come OnTouchListener privato, quindi tutto il codice di rilevamento dello scorrimento sarebbe in un unico posto.

Incolla il codice seguente nella tua implementazione ScrollView:

private class ScrollFinishHandler implements OnTouchListener
{
        private static final int SCROLL_TASK_INTERVAL = 100;

        private Runnable    mScrollerTask;
        private int         mInitialPosition = 0;

        public ScrollFinishHandler()
        {
            mScrollerTask = new Runnable() {

                public void run() {

                    int newPosition = getScrollY();
                    if(mInitialPosition - newPosition == 0)
                    {//has stopped

                       onScrollStopped(); // Implement this on your main ScrollView class
                    }else{
                        mInitialPosition = getScrollY();
                        ExpandingLinearLayout.this.postDelayed(mScrollerTask, SCROLL_TASK_INTERVAL);
                    }
                }
            };
        }

        @Override
        public boolean onTouch(View v, MotionEvent event) 
        {
            if (event.getAction() == MotionEvent.ACTION_UP) 
            {

                startScrollerTask();
            }
            else
            {
                stopScrollerTask();
            }

            return false;
        }

}

E poi nella tua implementazione ScrollView:

setOnTouchListener( new ScrollFinishHandler() );

-1
        this.getListView().setOnScrollListener(new OnScrollListener(){
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {}

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
                     if( firstVisibleItem + visibleItemCount >= totalItemCount ) 
                              // Last item is shown...

            }

Spero che lo snippet aiuti :)


Purtroppo sto usando uno ScrollView, non un ListView. Grazie comunque.
user1053691

1
Ciao? ScrollView non ListView.
Kevin Parker
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.