2010-08-19 19 views
6

Situación: Tengo dos ScrollView dentro de cada uno de los dos HorizontalScrollView de un TableRow.

Objetivo: Cuando toco arrastrar uno de ScrollView, otro ScrollView debe desplazarse tanto. Por ejemplo, si tengo una lista de nombre en ScrollView a la izquierda y los números de teléfono correspondientes en ScrollView a la derecha, desplazar un ScrollView no debe destruir el límite original entre los nombres y números de teléfono.
Sincronizar dos ScrollView

¿Puede ser implementado por onTouchEvent? De ser así, ¿cómo debería implementar esto (en ambos o en uno de ScrollView)?

Por favor, ¡ayúdame Android Gurus!

+0

has necesitado extender ScrollView a usted puede reemplazar el método onTouchEvent y el uso que llaman onTouchEvent en su otra ScrollView y pasarlo el mismo evento? – schwiz

Respuesta

12

tengo una solución simple que funciona para mí:

  • subclase ambos ScrollView s y anular su caso onScrollChanged para actualizar ScrollManager al desplazarse cambios:

    public interface ScrollNotifier { 
        public void setScrollListener(ScrollListener scrollListener); 
    
        public ScrollListener getScrollListener(); 
    } 
    
    public class SyncedScrollView extends ScrollView implements ScrollNotifier { 
    
        //... 
    
        private ScrollListener scrollListener = null; 
    
        @Override 
        protected void onScrollChanged(int l, int t, int oldl, int oldt) { 
         super.onScrollChanged(l, t, oldl, oldt); 
         if (scrollListener != null) 
          scrollListener.onScrollChanged(this, l, t, oldl, oldt); 
        } 
        @Override 
        public void setScrollListener(ScrollListener scrollListener) { 
         this.scrollListener = scrollListener; 
        } 
        @Override 
        public ScrollListener getScrollListener() { 
         return scrollListener; 
        } 
    } 
    
  • crear una clase ScrollManager que coordina el desplazamiento de múltiples participantes

    public interface ScrollListener { 
        void onScrollChanged(View syncedScrollView, int l, int t, int oldl, 
         int oldt); 
    } 
    
    public class ScrollManager implements ScrollListener { 
        private static final int SCROLL_HORIZONTAL = 1; 
        private static final int SCROLL_VERTICAL = 2; 
    
        private ArrayList<ScrollNotifier> clients = new ArrayList<ScrollNotifier>(4); 
    
        private volatile boolean isSyncing = false; 
        private int scrollType = SCROLL_HORIZONTAL; 
    
        public void addScrollClient(ScrollNotifier client) { 
         clients.add(client); 
         client.setScrollListener(this); 
        } 
    
        // TODO fix dependency on all views being of equal horizontal/ vertical 
        // dimensions 
        @Override 
        public void onScrollChanged(View sender, int l, int t, int oldl, int oldt) { 
         // avoid notifications while scroll bars are being synchronized 
         if (isSyncing) { 
          return; 
         } 
    
         isSyncing = true; 
    
         // remember scroll type 
         if (l != oldl) { 
          scrollType = SCROLL_HORIZONTAL; 
         } else if (t != oldt) { 
          scrollType = SCROLL_VERTICAL; 
         } else { 
          // not sure why this should happen 
          isSyncing = false; 
          return; 
         } 
    
         // update clients 
         for (ScrollNotifier client : clients) { 
          View view = (View) client; 
          // don't update sender 
          if (view == sender) { 
           continue; 
          } 
    
          // scroll relevant views only 
          // TODO Add support for horizontal ListViews - currently weird things happen when ListView is being scrolled horizontally 
          if ((scrollType == SCROLL_HORIZONTAL && view instanceof HorizontalScrollView) 
            || (scrollType == SCROLL_VERTICAL && view instanceof ScrollView) 
            || (scrollType == SCROLL_VERTICAL && view instanceof ListView)) { 
           view.scrollTo(l, t); 
          } 
         } 
    
         isSyncing = false; 
        } 
    } 
    
  • crear la costumbre ScrollView s y establezca el ScrollManager para la notificación en ambos

    private void setupScrolling() { 
        ScrollNotifier view; 
        ScrollManager scrollManager = new ScrollManager(); 
    
        // timeline horizontal scroller 
        view = (ScrollNotifier) findViewById(R.id.epgtimeline_container); 
        scrollManager.addScrollClient(view); 
    
        // services vertical scroller 
        view = (ScrollNotifier) findViewById(R.id.epgservices_container); 
        scrollManager.addScrollClient(view); 
    
        // content area scrollers 
        view = (ScrollNotifier) findViewById(R.id.epgevents_container_inner); 
        scrollManager.addScrollClient(view); 
        view = (ScrollNotifier) findViewById(R.id.epgevents_container_outer); 
        scrollManager.addScrollClient(view); 
    } 
    
+1

Excelente respuesta, me estaba rompiendo la cabeza en esto por 2 días tratando de usar el evento onTouchEvent y pasar ese canal. Finalmente funcioné, pero solo funcionó de una manera ... esto soluciona todos mis problemas ... ;-) ... casi todos mis problemas jaja – stackr

1

Gracias a andig para una tan gran synching scrollview solution.

Pero hay poca demora entre ambas vistas de desplazamiento mientras se arroja.

Así que estoy escribiendo aquí la solución extendida para eliminar ese retraso entre ambos scrollview.

Acabo de utilizar la clase OverScroller y he manejado el evento fling manualmente en SyncedScrollView.

Simplemente tiene que reemplazar SyncedScrollView con el siguiente código. Utiliza otras clases de andig's solution

import android.content.Context; 
import android.support.v4.view.ViewCompat; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.widget.OverScroller; 
import android.widget.ScrollView; 

/** 
* Created by mitul.varmora on 11/7/2016. 
* SyncedScrollView 
* https://stackoverflow.com/questions/3527119/sync-two-scrollview 
*/ 
public class SyncedScrollView extends ScrollView implements ScrollNotifier { 

    private ScrollListener scrollListener = null; 

    private OverScroller scroller; 
    private Runnable scrollerTaskRunnable; 

    public SyncedScrollView(Context context) { 
     super(context); 
     init(); 
    } 

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

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

    private void init() { 

     scroller = new OverScroller(getContext()); 
     scrollerTaskRunnable = new Runnable() { 
      @Override 
      public void run() { 
       scroller.computeScrollOffset(); 

       smoothScrollTo(0, scroller.getCurrY()); 

       if (!scroller.isFinished()) { 
        SyncedScrollView.this.post(this); 
       } else { 
        //deceleration ends here, do your code 
        ViewCompat.postInvalidateOnAnimation(SyncedScrollView.this); 
       } 
      } 
     }; 
    } 

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

    @Override 
    public ScrollListener getScrollListener() { 
     return scrollListener; 
    } 

    @Override 
    public void setScrollListener(ScrollListener scrollListener) { 
     this.scrollListener = scrollListener; 
    } 

    @Override 
    public void fling(int velocityY) { 

     scroller.forceFinished(true); 
     scroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0, getChildAt(0).getHeight()); 
     post(scrollerTaskRunnable); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
//  return super.onTouchEvent(ev); 
     boolean eventConsumed = super.onTouchEvent(ev); 
     if (eventConsumed && ev.getAction() == MotionEvent.ACTION_UP) { 
      if (scroller.isFinished()) { 
       //do your code 
      } 
     } 
     return eventConsumed; 
    } 
}