Situation: I have two ScrollView inside of each of two HorizontalScrollView of a TableRow.
Goal: When I touch drag one of ScrollView, another ScrollView must scroll as much. For instance, if I have a list of name on left ScrollView and corres开发者_如何学Cponding phone numbers in right ScrollView, scrolling one ScrollView should not destroy the original bounding between the names and phone numbers.Can it be implemented by onTouchEvent? If so, how should I implement this(on both or one of the ScrollView)?
Please help me out Android Gurus!
I have a simple solution that works for me:
- subclass both - ScrollViews and override their- onScrollChangedevent to update- ScrollManagerwhen scrolling changes:- 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; } }
- create a - ScrollManagerclass that coordinates the scrolling of multiple participants- 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; } }
- create the custom - ScrollViews and set the- ScrollManagerfor notification on both- 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); }
Thanks to andig for such a great synching scrollview solution.
But there is little bit lag between both scrollviews while flinging.
So i am writing here extended solution to remove that lag between both scrollview.
I have just used OverScroller class and handled fling event manually in SyncedScrollView.
You have to just replace SyncedScrollView with below code. Use other classes from 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;
    }
}
 
         
                                         
                                         
                                         
                                        ![Interactive visualization of a graph in python [closed]](https://www.devze.com/res/2023/04-10/09/92d32fe8c0d22fb96bd6f6e8b7d1f457.gif) 
                                         
                                         
                                         
                                         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论