滚动视图同步问题

Scrollviews synchronisation issue

我写了一个小应用程序,显示 2 个并排的滚动视图。我需要同步 2 个滚动视图的滚动位置。为此,我扩展了 ScrollView 并覆盖了 onScrollChanged 以在发生滚动时得到通知,然后同步 2 个滚动视图。

我的两个滚动视图显示一堆蓝色视图。左边scrollView是红色背景,右边是绿色背景。

这是左侧 scrollView 滚动时发生的情况:

=> 同步正常

下面是右侧 scrollView 滚动时发生的情况:

=> 同步不好,有差距

(两个屏幕截图都是在 scrollviews 浏览期间截取的)

两种情况如何同步好?

我的Activity、我的scrollView和我的scrollView容器的代码是here

您似乎遇到了系统限制 - 系统按照在您的 XML 中声明的顺序绘制视图。

因此,当您抛出第一个声明的 ScrollView 时,第二个会更新,但第一个不会再次更新。然而,当你扔第二个时,第一个得到更新,然后第二个得到更新,变化反映到第一个并再次更新。

我不确定上述描述是否 100% 准确,但大致是这样。

我创建了一个测试用例来检查我的假设,用以下内容代替 main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_layout">


    <View android:id="@+id/separator_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerHorizontal="true"
        android:visibility="invisible"/>


    <com.example.www.syncscrollviewtesting_Whosebug.ObservableScrollView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_alignParentEnd="true"
        android:layout_toEndOf="@id/separator_view"
        android:background="@android:color/holo_green_light"
        android:id="@+id/left_scrollview">
        <com.example.www.syncscrollviewtesting_Whosebug.Container
            android:layout_width="match_parent"
            android:layout_height="100000dp"
            android:minHeight="100000dp"
            android:id="@+id/left_container"/>

    </com.example.www.syncscrollviewtesting_Whosebug.ObservableScrollView>


    <com.example.www.syncscrollviewtesting_Whosebug.ObservableScrollView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:layout_toStartOf="@id/separator_view"
        android:background="@android:color/holo_red_dark"
        android:id="@+id/right_scrollview">
        <com.example.www.syncscrollviewtesting_Whosebug.Container
            android:layout_width="match_parent"
            android:layout_height="100000dp"
            android:minHeight="100000dp"
            android:id="@+id/right_container"/>
    </com.example.www.syncscrollviewtesting_Whosebug.ObservableScrollView>

</RelativeLayout>

上面的 XML 允许您将两个 ScrollView 放置在 separator_view 的两侧。我发现无论你如何定位它们,ScrollView 的红色背景(第二个声明)总是会导致 "lag",而绿色背景的 ScrollView 会起作用很好。

我还试图通过将此添加到他们的代码中来防止对 ScrollView 进行不必要的更新:

   @Override
   protected void onScrollChanged(int x, int y, int oldx, int oldy) {
      super.onScrollChanged(x, y, oldx, oldy);
      if (!mIsDisabled && scrollViewListener != null) {
         scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
      }
   }

   public void setDisabled(boolean isDisabled) {
      mIsDisabled = isDisabled;
   }

   @Override
   public boolean onTouchEvent(MotionEvent ev) {
      if (mIsDisabled)
         return false; // Ignore touch event when disabled
      else
         return super.onTouchEvent(ev);
   }

... 这对 Activity 的:

   @Override
   public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
      if (scrollView == mRightScrollView) {
         mLeftScrollView.setDisabled(true);
         mLeftScrollView.setScrollY(y);
         mLeftScrollView.setDisabled(false);
      } else {
         mRightScrollView.setDisabled(true);
         mRightScrollView.setScrollY(y);
         mRightScrollView.setDisabled(false);
      }

   }

但也没用...

所以,我猜,你最好找到另一种方法,它不涉及重新绘制一大堆 Views,或者只接受 "lag".

解法: 根据我对情况的分析,这个解决方案是OP自己提供的:触摸事件可以从右边ScrollView(在XML中声明为第二个)转发到左边ScrollView。这样,考虑到左侧的滑动 ScrollView 不会导致延迟,所有触摸事件都被视为由第一个声明的 ScrollView 发起,并且避免了延迟。

很抱歉我之前的回答没有正确研究您的问题。

如我所说,我认为您无法在完全没有任何延迟的情况下正确同步 2 ScrollView。但是您仍然可以使用单个视图。

这有点棘手,因为您还想将拆分分成具有权重属性的相等部分。

可以找到解决方案here。在此基础上,我提出了以下代码:

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <View
            android:id="@+id/spacer"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_centerHorizontal="true"/>
        <LinearLayout
            android:id="@+id/left"
            android:layout_alignRight="@id/spacer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            ...
        </LinearLayout>
        <LinearLayout
            android:id="@+id/right"
            android:layout_alignLeft="@id/spacer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            ...
        </LinearLayout>
    </RelativeLayout>
</ScrollView>

然后当您想要切换 leftright 视图重叠时调用此:

leftParams.addRule(RelativeLayout.ALIGN_RIGHT, 0);
rightParams.addRule(RelativeLayout.ALIGN_LEFT, 0);

leftParams.addRule(RelativeLayout.ALIGN_RIGHT, R.id.spacer);
rightParams.addRule(RelativeLayout.ALIGN_LEFT, R.id.spacer);

设置参数后,您需要重绘视图:

left.requestLayout();
right.requestLayout();

可在 this GitHub page.

上找到工作示例