J'ai 2 ScrollViews dans ma disposition Android. Comment puis-je synchroniser leurs positions de défilement?
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 rendu protégé et n'ont pas ajouté de hook "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);
}
Ensuite, nous devons remplacer la classe ScrollView, pour fournir le 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);
}
}
}
Et nous devons spécifier cette nouvelle classe ObservableScrollView dans la disposition, au lieu des balises ScrollView existantes.
<com.test.ObservableScrollView
Android:id="@+id/scrollview1"
... >
...
</com.test.ObservableScrollView>
Enfin, nous avons tout rassemblé dans la 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);
}
}
}
Le code scrollTo () prend en charge toutes les conditions de boucle pour nous, nous n'avons donc pas à nous en préoccuper. La seule mise en garde est que cette solution n'est pas garantie de fonctionner dans les futures versions d'Android, car nous remplaçons une méthode protégée.
Une amélioration de la solution d'Andy: dans son code, il utilise scrollTo, le problème est que si vous lancez une vue de défilement dans une direction puis une autre dans une autre direction, vous remarquerez que la première n'arrête pas sa précédente aventure mouvement.
Cela est dû au fait que scrollView utilise computeScroll () pour effectuer ses gestes et qu'il entre en conflit avec scrollTo.
Pour éviter cela, programmez simplement onScrollChanged de cette façon:
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ée qui pourrait être utilisée pour empêcher le scrollView de voler (mais il y en a peut-être d'autres que j'ai ratés!)
Pour accéder à cette fonction (qui est protégée), vous devez l'ajouter à votre ObservableScrollViewer
public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
Pourquoi ne pas simplement implémenter OnTouchListener
dans votre activité. Remplacez ensuite la méthode onTouch, puis obtenez la position de défilement de la première ScrollViewOne.getScrollY()
et mettez à jour ScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());
Juste une autre idée ... :)
Dans le package Android support-v4, Android fournissez une nouvelle classe nommée NestedScrollView
).
nous pouvons remplacer le <ScrollView>
noeud avec <Android.support.v4.widget.NestedScrollView>
dans la mise en page xml, et implémente son NestedScrollView.OnScrollChangeListener
in Java pour gérer le défilement.
Cela rend les choses plus faciles.