【问题标题】:Scrollviews synchronisation issue滚动视图同步问题
【发布时间】:2015-06-02 12:14:39
【问题描述】:

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

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

这是在左侧滚动视图上滚动时发生的情况:

=> 同步正常

这是在右侧滚动视图上滚动时发生的情况:

=> 同步不好,有差距

(两个屏幕截图都是在滚动视图的投掷过程中拍摄的)

如何在这两种情况下进行良好的同步?

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

【问题讨论】:

  • 为什么使用两个 ScrollView 而不是一个?
  • 我同意@Médéric 为什么不只使用 1?
  • 因为在某些时候,我需要一个重叠另一个。
  • 是的,毕竟你是对的。起初我没有意识到问题出在哪里。我的错。不要认为你可以通过两个ScrollViews 来避免这种延迟。当您说一个需要重叠另一个时,您是什么意思?
  • @Simas 我的意思是我想将一个滚动视图放在另一个滚动视图上。这就是为什么我不能在一个滚动视图中连接 2 个内容。

标签: android scrollview


【解决方案1】:

您似乎遇到了系统限制 - 系统按照在您的 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_stackoverflow.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_stackoverflow.Container
            android:layout_width="match_parent"
            android:layout_height="100000dp"
            android:minHeight="100000dp"
            android:id="@+id/left_container"/>

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


    <com.example.www.syncscrollviewtesting_stackoverflow.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_stackoverflow.Container
            android:layout_width="match_parent"
            android:layout_height="100000dp"
            android:minHeight="100000dp"
            android:id="@+id/right_container"/>
    </com.example.www.syncscrollviewtesting_stackoverflow.ObservableScrollView>

</RelativeLayout>

上述 XML 允许您将两个 ScrollViews 定位在 separator_view 的两侧。我发现无论你如何定位它们,带有红色背景(声明为第二个)的ScrollView 总是会导致“滞后”,而带有绿色背景的ScrollView 则可以正常工作。

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

   @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 的方法,或者只是接受“滞后”。

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

【讨论】:

  • 子位置确实与存在同步问题的滚动视图相关联。作为一种解决方法,当右侧滚动视图发生触摸时,我将其转发到左侧滚动视图。这是一个 hack,但这是我发现的唯一解决方案,可以让 2 个滚动视图始终保持同步。
  • @MartinMoizard,我什至没有想过这个简单的解决方案。它的简单巧妙!感谢您的回复 - 如果您不介意,我会将其添加到答案中。
【解决方案2】:

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

正如我所说,我认为您无法正确同步 2 ScrollViews 而不会出现任何延迟。但是,您仍然可以使用单个视图。

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

可以在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 上找到一个工作示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 2011-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多