2010-08-19 15 views
6

Situazione: Ho due ScrollView all'interno di ciascuno di due HorizontalScrollView di un TableRow.

Obiettivo: Quando tocco una di ScrollView, è necessario scorrere un'altra ScrollView. Ad esempio, se ho un elenco di nomi sulla sinistra di ScrollView e i numeri di telefono corrispondenti nella destra di ScrollView, scorrere uno ScrollView non dovrebbe distruggere il confine originale tra i nomi e i numeri di telefono.
Sync Two ScrollView

Può essere implementato da onTouchEvent? In tal caso, come dovrei implementarlo (su entrambi o su ScrollView)?

Per favore aiutatemi Guru Android!

+0

hai provato estendere ScrollView a voi può sovrascrivere il metodo onTouchEvent e l'uso che per chiamare onTouchEvent sull'altro ScrollView e passarlo lo stesso evento? – schwiz

risposta

12

Ho una semplice soluzione che funziona per me:

  • sottoclasse sia ScrollView s e sovrascrivere il loro evento onScrollChanged aggiornare ScrollManager durante lo scorrimento cambia:

    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; 
        } 
    } 
    
  • creare una classe ScrollManager che coordina lo scorrimento di più partecipanti

    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; 
        } 
    } 
    
  • creare il costume ScrollView s e impostare il ScrollManager per la notifica su entrambi i

    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

Risposta superba, mi sono rotto la testa su questo per 2 giorni ora cercando di usare l'onTouchEvent e passando quella depressione. Finalmente ho funzionato, ma ha funzionato solo in un modo .. questo risolve tutti i miei problemi ... ;-) ... quasi tutti i miei problemi haha – stackr

1

Grazie ad andig per una così grande synching scrollview solution.

Ma c'è un po 'di ritardo tra entrambe le visualizzazioni di scorrimento mentre si lancia.

Quindi sto scrivendo qui una soluzione estesa per rimuovere il ritardo tra entrambe le scrollview.

Ho appena usato la classe OverScroller e gestito l'evento fling manualmente in SyncedScrollView.

Devi solo sostituire SyncedScrollView con il codice sottostante. Utilizza altre classi da 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; 
    } 
}