Posso avere onScrollListener per uno ScrollView?


140

Sto usando a HorizontalScrollViewin un layout e ho bisogno di identificare l'utente ha raggiunto il punto iniziale e finale della pergamena.

Perché ListViewho provato un onScrollListenere è possibile trovare il punto iniziale e finale di scorrimento.

Ho provato a fare lo stesso nel mio Scrollviewma non sembra possibile. Esistono altri modi possibili per ottenere ciò di cui ho bisogno?


3
È possibile. Vedi la risposta dell'utente2695685. In breve, il seguente in onStartfarà il trucco: hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});in onStart () dove hsvè un HorizontalScrollViewfunziona.
— JohnnyLambada,

accetta qualcuno di utile risposta..se pubblica la tua risposta ..
— Ranjith Kumar,

12
Perché rilevare un evento di scorrimento con ScrollView è così difficile in Android? Questo è impazzito.
— funzionato il

Risposte:


389

Ogni istanza di Visualizza chiamate getViewTreeObserver(). Ora, quando si tiene un caso di ViewTreeObserver, è possibile aggiungere un OnScrollChangedListener()ad esso utilizzando il metodo addOnScrollChangedListener().

Puoi vedere ulteriori informazioni su questa classe qui .

Ti consente di essere a conoscenza di ogni evento a scorrimento, ma senza le coordinate. Puoi ottenerli utilizzando getScrollY()o getScrollX()dall'interno dell'ascoltatore.

scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        int scrollY = rootScrollView.getScrollY(); // For ScrollView
        int scrollX = rootScrollView.getScrollX(); // For HorizontalScrollView
        // DO SOMETHING WITH THE SCROLL COORDINATES
    }
});

6
Questa risposta dovrebbe essere contrassegnata come corretta. hsv.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {@Override public void onScrollChanged() {Log.i(TAG,"scroll:"+hsv.getScrollX());}});in onStart () dove si hsvtrova un'opera HorizontalScrollView. Sospetto che lo stesso funzionerà anche con ScrollView.
— JohnnyLambada,

3
Esattamente. questa è la risposta migliore non è necessario estendere HorizontalScrollView. Appena testato con ScrollView, funziona alla grande: final ScrollView sv = (ScrollView) findViewById (R.id.scrollViewArticle); sv.getViewTreeObserver (). addOnScrollChangedListener (new ViewTreeObserver.OnScrollChangedListener () {@Override public void onScrollChanged () {Log.d ("onScrollChanged Y", String.valueOf (sv.getScroll}))
— Raffaello C,

5
Dovresti prima controllare ViewTreeObserver.isAlive ()
— M.Salomaa

6
Il codice di esempio nella risposta introduce una perdita di memoria. Poiché il metodo è adde non set, tutti i listener verranno conservati fino a quando non verranno rimossi esplicitamente. Quindi la classe anonima utilizzata come implementazione di listener nell'esempio perderà (insieme a tutto ciò a cui fa riferimento, ovvero la classe esterna).
— Brett Duncavage,

7
Probabilmente una domanda stupida, ma cos'è rootScrollView?
— Iqbal,

49

Questo potrebbe essere molto utile. Usa NestedScrollViewinvece di ScrollView. Libreria di supporto 23.1 ha introdotto un OnScrollChangeListenera NestedScrollView. Quindi puoi fare qualcosa del genere.

 myScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            Log.d("ScrollView","scrollX_"+scrollX+"_scrollY_"+scrollY+"_oldScrollX_"+oldScrollX+"_oldScrollY_"+oldScrollY);
            //Do something
        }
    });

2
Sicuramente più semplice che tenere traccia del fatto che tu abbia aggiunto il listener prima con getViewTreeObserver (). Grazie!
— Anthony Mills,

Ma come utilizzare NestedScrollView come vista di scorrimento orizzontale? Impossibile trovare alcuna risorsa
— GensaGames

Cosa succede se desidero utilizzare lo scorrimento orizzontale?
— Nikita Axyonov,

7
@ dazed'n'confused NestedScrollViewfa parte della libreria di supporto, il suo setOnScrollChangeListenermetodo non ha requisiti minimi di versione.
— Tom

4
Non confondere con View's setOnScrollChangeListenerche richiede livello API 23
— Anders Ullnæss

18

Ecco un HorizontalScrollView derivato che ho scritto per gestire le notifiche relative allo scorrimento e alla fine dello scorrimento. Gestisce correttamente quando un utente ha smesso di scorrere attivamente e quando rallenta completamente dopo che un utente ha lasciato andare:

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;
    }

}

1
Sembra che sia meglio dell'uso del metodo ViewTreeObserver. Solo perché quando hai un'attività in cui hai caricato più frammenti (ad esempio 3 frammenti con schede scorrevoli) con ListViews e ScrollViews e devi registrare eventi per una vista specifica. Considerando che se ViewTreeObserver è registrato, genererà eventi anche se non è attiva.
— Torsten Ojaperv,

3
@ZaBlanc - Per favore, puoi chiamarmi come inizializzare questa classe e gli ascoltatori dalla mia attività, che contiene ScrollView? L'ho implementato bene, ma gli ascoltatori non restituiranno ancora alcun valore.
— Edmond Tamas,

Questo funziona davvero! e non c'è bisogno di sdk> 23 per questo :)
— Matan Dahan,

5

Se si desidera conoscere la posizione di scorrimento di una vista, è possibile utilizzare la seguente funzione di estensione nella classe Vista:

fun View?.onScroll(callback: (x: Int, y: Int) -> Unit) {
    var oldX = 0
    var oldY = 0
    this?.viewTreeObserver?.addOnScrollChangedListener {
        if (oldX != scrollX || oldY != scrollY) {
            callback(scrollX, scrollY)
            oldX = scrollX
            oldY = scrollY
        }
    }
}

5

Puoi usare NestedScrollViewinvece di ScrollView. Tuttavia, quando si utilizza un Lambda Kotlin, non saprà che si desidera NestedScrollView setOnScrollChangeListenerinvece di quello a View (che è il livello API 23). È possibile risolvere questo problema specificando il primo parametro come NestedScrollView.

nestedScrollView.setOnScrollChangeListener { _: NestedScrollView, scrollX: Int, scrollY: Int, _: Int, _: Int ->
    Log.d("ScrollView", "Scrolled to $scrollX, $scrollY")
}

Questa dovrebbe essere la risposta accettata perché il metodo che utilizza viewTreeObserver provoca perdite di memoria e deve essere rimosso manualmente, altrimenti verranno aggiunti più osservatori di scorrimento.
— Ray Li

1
    // --------Start Scroll Bar Slide--------
    final HorizontalScrollView xHorizontalScrollViewHeader = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewHeader);
    final HorizontalScrollView xHorizontalScrollViewData = (HorizontalScrollView) findViewById(R.id.HorizontalScrollViewData);
    xHorizontalScrollViewData.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int scrollX; int scrollY;
            scrollX=xHorizontalScrollViewData.getScrollX();
            scrollY=xHorizontalScrollViewData.getScrollY();
            xHorizontalScrollViewHeader.scrollTo(scrollX, scrollY);
        }
    });
    // ---------End Scroll Bar Slide---------

prova ad aggiungere una descrizione per supportare il tuo codice che farà capire a tutti la pastella
— Aniruddha Das,

Questo codice è molto simile a un'altra risposta , no?
— Sergii,

1

è possibile definire una classe ScrollView personalizzata e aggiungere un'interfaccia da chiamare durante lo scorrimento in questo modo:

public class ScrollChangeListenerScrollView extends HorizontalScrollView {


private MyScrollListener mMyScrollListener;

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

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

public ScrollChangeListenerScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}


public void setOnMyScrollListener(MyScrollListener myScrollListener){
    this.mMyScrollListener = myScrollListener;
}


@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    if(mMyScrollListener!=null){
        mMyScrollListener.onScrollChange(this,l,t,oldl,oldt);
    }

}

public interface MyScrollListener {
    void onScrollChange(View view,int scrollX,int scrollY,int oldScrollX, int oldScrollY);
}

}
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.