4

I have two horizontal scrollview, and want to keep them always at the same position / distance. If user scrolls one, need to scroll programmatically the other. The challenge is, that an infinite loop will occur. One will raise the other, other will raise first. How can I set a state, indicate that a user initiated scroll is still in progress? So other scrollview should not execute the programmatic scroll.

One of them is a HorizontalScrollView other is a RecyclerView.

Tried solutions like below, without any success:

horizontalScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {

            if (programmaticScrollEnable) {
                programmaticScrollEnable = false;
                // do programmatic scrolling here
                programmaticScrollEnable = true;
            }
        }
    });        

Tried to change state in onScrollStateChanged method:

@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);

    /*if (newState == RecyclerView.SCROLL_STATE_IDLE) {
        MainActivity.programmaticScrollEnable = true;
    }*/
}
Zain
  • 37,492
  • 7
  • 60
  • 84
János
  • 32,867
  • 38
  • 193
  • 353

2 Answers2

0

Try this...

horizontalScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {

    @Override
    public void onScrollChanged() {

   recyclerView.scrollTo(horizontalScrollView.scrollTo(horizontalScrollView.getScrollX(), 0);

    }
});
  • any idea about this one : https://stackoverflow.com/questions/58848391/how-do-i-synchronize-scrollview-positions-of-dynamic-horizontal-scroll-views-ins –  Nov 14 '19 at 11:21
0

The challenge is, that an infinite loop will occur.

You can avoid the infinite loop by registering the last touched ScrolledView in OnTouchListener. This touched ScrollView must not scroll programmatically; but the other(s) should be.

This can be tracked by setting a tag to each ScrollView and compare that tag during scroll event.

If you are API level 23 (Android M), you can register View.OnScrollChangeListener. And for APIs below that, you can register ViewTreeObserver.OnScrollChangedListener. But the latter is heavy on the resources; so you need to handle that.

For API levels 23+

// Tracking last touched SV
private var touchedSVTag = -1

// list of ScrollViews
val svs = arrayListOf(scrollview1, scrollview2)

val scrollListener =
    View.OnScrollChangeListener { view, scrollX, _, _, _ ->

        val currentSVTag = view!!.tag as Int

        if (currentSVTag == touchedSVTag) {
            for (svTag in 0 until svs.size) 
                if (svTag != currentSVTag) 
                    svs[svTag].scrollTo(scrollX, 0)
        }
    }

val itemTouchListener = View.OnTouchListener { sv, _ ->
    val svTag = sv.tag as Int

    if (touchedSVTag != -1 && touchedSVTag != svTag) {
        // stop scrollView in the middle of the scroll
        svs[touchedSVTag].fling(0)
    }

    touchedSVTag = svTag
    false
}

for (i in 0 until svs.size) {
    val sv = svs[i]
    sv.tag = i
    sv.setOnScrollChangeListener(scrollListener)
    sv.setOnTouchListener(itemTouchListener)
}

And for API levels below 23:

// Tracking last touched SV
private var touchedSVTag = -1

// list of ScrollViews
val svs = arrayListOf(scrollview1, scrollview2)

val scrollListener = {
    val scrolledSV = svs[touchedSVTag]
    for (svTag in 0 until svs.size) 
        if (svTag != touchedSVTag)
            svs[svTag].scrollTo(scrolledSV.scrollX, 0)
}

val itemTouchListener = View.OnTouchListener { sv, _ ->
    val svTag = sv.tag as Int

    if (touchedSVTag != -1 && touchedSVTag != svTag) {
        // stop scrollView in the middle of the scroll
        svs[touchedSVTag].fling(0)
    }

    touchedSVTag = svTag
    false
}

for (i in 0 until svs.size) {
    val sv = svs[i]
    sv.tag = i
    sv.viewTreeObserver.addOnScrollChangedListener(scrollListener)
    sv.setOnTouchListener(itemTouchListener)
}
Zain
  • 37,492
  • 7
  • 60
  • 84