Synchroniser le ScrollView les positions de défilement - android

j'ai 2 ScrollViews sur mon Android. Comment synchroniser leurs positions de défilement?

92
demandé sur Tim 2010-10-16 16:41:50

4 réponses

il y a une méthode dans ScrollView...

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

malheureusement Google N'a jamais pensé que nous aurions besoin d'y accéder, c'est pourquoi ils l'ont fait protégé et n'ont pas ajouté un crochet "setOnScrollChangedListener". Nous devrons donc le faire pour nous-mêmes.

nous avons D'abord besoin d'une interface.

package com.test;

public interface ScrollViewListener {

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

}

alors nous devons surcharger la classe ScrollView, pour fournir le crochet 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);
        }
    }

}

et nous devrions spécifier cette nouvelle classe ObservableScrollView dans le layout, au lieu des balises ScrollView existantes.

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

    ...

</com.test.ObservableScrollView>

enfin, nous avons tout regroupé dans la classe de mise en page.

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

}

le code scrollTo() s'occupe de toutes les conditions de boucle pour nous, donc nous n'avons pas besoin de nous inquiéter à ce sujet. Le seul inconvénient est que cette solution n'est pas garanti dans les futures versions d'Android, parce que nous sommes primordial une méthode protégée.

285
répondu Andy 2010-10-17 09:06:25

une amélioration à la solution D'Andy : Dans son code, il utilise scrollTo, le problème est, si vous lancez un scrollview dans une direction et puis fling un autre dans une autre direction, vous remarquerez que le premier ne s'arrête pas son mouvement de fling précédent.

cela est dû au fait que scrollView utilise computeScroll() pour faire ses gestes, et entre en conflit avec scrollTo.

pour éviter cela, il suffit de programmer le onscroll changea ainsi:

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

avec interceptScroll un booléen statique initialisé à true. (cela permet d'éviter les boucles infinies sur ScrollChanged)

onOverScrolled est la seule fonction que j'ai trouvé qui pourrait être utilisée pour empêcher le scrollView de clignoter (mais il pourrait y en avoir d'autres que j'ai manqué !)

pour accéder à cette fonction (qui est protégée) , vous devez l'ajouter à votre fichier ObservableScrollViewer

public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
10
répondu Taiko 2012-12-19 17:06:54

Pourquoi ne pas simplement implémente OnTouchListener dans votre activité. Puis outrepasser la méthode onTouch, puis obtenir la position de défilement de la première ScrollViewOne.getScrollY() et mettre à jour ScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());

juste une autre idée... :)

5
répondu Aaron Newton 2012-03-13 21:15:27

dans le soutien Android-v4 package, Android fournir une nouvelle classe appelée NestedScrollView .

nous pouvons remplacer le noeud <ScrollView> par <android.support.v4.widget.NestedScrollView> dans la mise en page xml, et implémente son NestedScrollView.OnScrollChangeListener en Java pour gérer le défilement.

Qui rend les choses plus faciles.

3
répondu wangzhangjian 2016-02-25 06:50:43