如何在Android中同步两个ScrollView的滚动?

4
我有两个水平的scrollview,想要让它们始终保持相同的位置/距离。如果用户滚动一个,则需要编程滚动另一个。挑战在于会出现无限循环。其中一个将引发另一个,另一个将首先引发。如何设置状态,指示用户启动的滚动仍在进行中?因此,其他scrollview不应执行编程滚动。
其中一个是HorizontalScrollView,另一个是RecyclerView
尝试了以下解决方案,但均未成功:
horizontalScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {

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

尝试在onScrollStateChanged方法中更改状态:

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

    /*if (newState == RecyclerView.SCROLL_STATE_IDLE) {
        MainActivity.programmaticScrollEnable = true;
    }*/
}
2个回答

0

试一下这个...

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

    @Override
    public void onScrollChanged() {

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

    }
});

你对这个问题有什么想法吗:https://stackoverflow.com/questions/58848391/how-do-i-synchronize-scrollview-positions-of-dynamic-horizontal-scroll-views-ins - user11455292

0
挑战在于会发生无限循环。
您可以通过在OnTouchListener中注册最后触摸的ScrolledView来避免无限循环。这个被触摸的ScrollView不能以编程方式滚动;但其他的应该可以。
这可以通过为每个ScrollView设置一个标签并在滚动事件期间比较该标签来跟踪。
如果您使用的是API级别23(Android M),则可以注册View.OnScrollChangeListener。对于低于该级别的API,您可以注册ViewTreeObserver.OnScrollChangedListener。但后者会占用大量资源,因此您需要处理它。
对于API级别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)
}

对于 API 级别低于 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)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接