Sincronizar posiciones de desplazamiento ScrollView – Android

Tengo 2 ScrollViews en mi diseño de Android. ¿Cómo puedo sincronizar sus posiciones de desplazamiento?

Hay un método en ScrollView …

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

Lamentablemente, Google nunca pensó que tendríamos que acceder a él, y es por eso que lo hicieron protegidos y no agregaron un gancho “setOnScrollChangedListener”. Entonces tendremos que hacer eso por nosotros mismos.

Primero, necesitamos una interfaz.

 package com.test; public interface ScrollViewListener { void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy); } 

Luego, tenemos que anular la clase ScrollView para proporcionar el enlace 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); } } } 

Y deberíamos especificar esta nueva clase ObservableScrollView en el diseño, en lugar de las tags ScrollView existentes.

  ...  

Finalmente, lo ponemos todo junto en la clase de Diseño.

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

El código scrollTo () se encarga de las condiciones de bucle para nosotros, por lo que no tenemos que preocuparnos por eso. La única advertencia es que no se garantiza que esta solución funcione en futuras versiones de Android, ya que estamos anulando un método protegido.

Una mejora de la solución de Andy: en su código, usa scrollTo, el problema es que si arrojas una vista de desplazamiento en una dirección y luego arrojas otra en otra dirección, notarás que la primera no detiene su aventura anterior movimiento.

Esto se debe al hecho de que scrollView usa computeScroll () para hacer sus gestos arrojadizos, y entra en conflicto con scrollTo.

Para evitar esto, simplemente programe el onScrollChanged de esta manera:

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

con intercepción Desplácese un booleano estático inicializado a verdadero. (Esto ayuda a evitar bucles infinitos en ScrollChanged)

onOverScrolled es la única función que encontré que podría usarse para evitar que scrollView se tirara (¡pero podría haber otros que me he perdido!)

Para acceder a esta función (que está protegida) debe agregar esto a su ObservableScrollViewer

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

¿Por qué no simplemente implementa OnTouchListener en su actividad? A continuación, anule el método onTouch, luego obtenga la posición de desplazamiento del primer ScrollViewOne.getScrollY() y actualice ScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());

Solo otra idea … 🙂

En el paquete Android v4 de soporte, Android proporciona una nueva clase llamada NestedScrollView .

podemos reemplazar el nodo con en el layout xml e implementamos su NestedScrollView.OnScrollChangeListener en Java para manejar el desplazamiento.

Eso hace las cosas más fáciles.