Sincronizza le posizioni di scorrimento di ScrollView - Android


95

Ho 2 ScrollView nel mio layout Android. Come posso sincronizzare le loro posizioni di scorrimento?

Risposte:


289

C'è un metodo in ScrollView ...

protected void onScrollChanged(int x, int y, int oldx, int oldy)

Sfortunatamente Google non ha mai pensato che avremmo avuto bisogno di accedervi, motivo per cui lo hanno protetto e non hanno aggiunto un hook "setOnScrollChangedListener". Quindi dovremo farlo per noi stessi.

Per prima cosa abbiamo bisogno di un'interfaccia.

package com.test;

public interface ScrollViewListener {

    void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);

}

Quindi dobbiamo sovrascrivere la classe ScrollView, per fornire l'hook ScrollViewListener.

package com.test;

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

public class ObservableScrollView extends ScrollView {

    private ScrollViewListener scrollViewListener = null;

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

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

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

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if(scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }

}

E dovremmo specificare questa nuova classe ObservableScrollView nel layout, invece dei tag ScrollView esistenti.

<com.test.ObservableScrollView
    android:id="@+id/scrollview1"
    ... >

    ...

</com.test.ObservableScrollView>

Infine, mettiamo tutto insieme nella classe Layout.

package com.test;

import android.app.Activity;
import android.os.Bundle;

public class Q3948934 extends Activity implements ScrollViewListener {

    private ObservableScrollView scrollView1 = null;
    private ObservableScrollView scrollView2 = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.q3948934);

        scrollView1 = (ObservableScrollView) findViewById(R.id.scrollview1);
        scrollView1.setScrollViewListener(this);
        scrollView2 = (ObservableScrollView) findViewById(R.id.scrollview2);
        scrollView2.setScrollViewListener(this);
    }

    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
        if(scrollView == scrollView1) {
            scrollView2.scrollTo(x, y);
        } else if(scrollView == scrollView2) {
            scrollView1.scrollTo(x, y);
        }
    }

}

Il codice scrollTo () si prende cura di qualsiasi condizione del ciclo per noi, quindi non dobbiamo preoccuparci di questo. L'unico avvertimento è che questa soluzione non è garantita per funzionare nelle versioni future di Android, perché stiamo sovrascrivendo un metodo protetto.


Ciao Andy Grazie per aver dedicato del tempo a fornire questa risposta - mi ha fatto andare avanti. Grazie ancora. Tim
Tim

-Andy sto anche usando il codice ma mi sta lanciando un'aspettativa di puntatore nullo, puoi aiutarmi
Hemant

@hemant Puoi per favore indicare in quale riga viene lanciato il NullPointer e con quale versione di Android stai lavorando?
sulai

Eroe del giorno: mi ha salvato la vita! = D
Pedrão

Ciao Andy, grazie per il codice. Funziona benissimo. Vorrei sapere una cosa [se tu o qualcuno1 avete ans. a questo] - Quando lancio il mio scrollView, il metodo onscrollchanged non registra tutte le coordinate X e Y mentre lo scrollview si muove. Mi dà solo la posizione di partenza e l'ultima posizione. Ad esempio, io inizio l'avventura da Y = 10 e lascio a Y = 30 e poi la velocità di lancio la porta a Y = 50 e poi si ferma. Quindi scorrendo sono cambiati solo i registri, forse 10, 11, 12..30 e poi 49, 50. Come faccio a registrare anche tutte le posizioni intermedie e ottenere tutte le coordinate da 10 a 50 ??
alchimista

11

Un miglioramento alla soluzione di Andy: nel suo codice, usa scrollTo, il problema è che se lanci uno scrollview in una direzione e poi ne lanci un altro in un'altra direzione, noterai che il primo non interrompe la sua precedente avventura movimento.

Ciò è dovuto al fatto che scrollView utilizza computeScroll () per eseguire i suoi gesti di lancio, ed entra in conflitto con scrollTo.

Per evitare ciò, basta programmare onScrollChanged in questo modo:

    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
    if(interceptScroll){
        interceptScroll=false;
        if(scrollView == scrollView1) {
            scrollView2.onOverScrolled(x,y,true,true);
        } else if(scrollView == scrollView2) {
            scrollView1.onOverScrolled(x,y,true,true);
        }
        interceptScroll=true;
    }
}

with interceptScroll un booleano statico inizializzato su true. (questo aiuta a evitare loop infiniti su ScrollChanged)

onOverScrolled è l'unica funzione che ho trovato che potrebbe essere utilizzata per fermare il lancio di scrollView (ma potrebbero essercene altre che mi sono perso!)

Per accedere a questa funzione (che è protetta) devi aggiungerla al tuo ObservableScrollViewer

public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}

2
Che bella cattura, figliolo!
Francisco

5

Perché non implementare solo OnTouchListenernella tua attività. Quindi sovrascrivi il metodo onTouch, quindi ottieni la posizione di scorrimento del primo ScrollViewOne.getScrollY()e aggiornaScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());

Solo un'altra idea ... :)


7
Questo può funzionare, ma quando tocchi e rilasci la visualizzazione a scorrimento può scorrere un po 'di più dopo aver lasciato andare che non viene catturato.
Richy

Come posso fare riferimento / ottenere il refrence di scrollView ScrollViewOne in questo caso in java?
Bunny Rabbit

Ci sono anche altri modi per scorrere (suTrackballEvent () per esempio)
surfealokesea

È un'ottima idea, ma invece di ottenere e impostare la posizione di scorrimento y, è più semplice inviare l'evento touch alla seconda visualizzazione di scorrimento. Ciò manterrà anche l '"avventura" nella seconda scrollview. MotionEvent newEvent = MotionEvent.obtain (evento); documentsScrollView.dispatchTouchEvent (newEvent);
Eduard Mossinkoff

3

Nel pacchetto Android support-v4, Android fornisce una nuova classe denominata NestedScrollView.

possiamo sostituire il <ScrollView>nodo con <android.support.v4.widget.NestedScrollView>nel layout xml e implementarlo NestedScrollView.OnScrollChangeListenerin Java per gestire lo scorrimento.

Questo rende le cose più facili.

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.