Scroll sync issue

I wrote a small application displaying 2 scrollViews next to each other. I need to scroll position of 2 scrollViews to sync. To do this, I extended the ScrollView and I overridden onScrollChanged to receive scroll notifications and then to sync 2 scrolls.

My two scrolling views show a bunch of blue views. The left scrollView has a red background and the right has a green background.

This is what happens with the scrollView on the left:
scroll on left scrollView
=> Synchronization is fine

And this is what happens with the scroll on the right scrollView:
scroll on right scrollView
=> The sync is not very good, there is a gap

(both screenshots were taken while scrolling)

How do I get good sync in both cases?

My activity code, my scrollView and my scrollView container are here .

+3


source to share


2 answers


It looks like you are using a system constraint here - the system draws views so that they are declared in your XML.

So when you throw the first one declared ScrollView

, the second one gets updated, but the first one doesn't get updated again. However, when you throw the second, the first is updated and the second is updated, the change is reflected to the first and it is updated again.

I'm not sure if the above description is 100% accurate, but it's something like that.

I created a test case to test my hypothesis, replacing the following for 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>

      

The above XML allows you to place both ScrollView

on either side of the separator_view

. I found out that no matter how you position them, a cast ScrollView

with a red background (declared second) always causes a "delay", and a flow ScrollView

with a green background works fine.

I also tried to prevent unnecessary updates ScrollView

by adding this to my code:



   @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);
   }

      

... and this is to Activity

's:

   @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);
      }

   }

      

but it did not help...

So, I think you'd better find another approach that doesn't involve redrawing the integer Views

, or just accept a "delay".

Solution: This solution was provided by the OP himself, based on my analysis of the situation: touch events can be routed from the right ScrollView

(declared second in XML) to the left ScrollView

. Thus, given that the outliers on the left ScrollView

do not cause delays, all touch events are treated as being fired first ScrollView

, and lag is prevented.

+1


source


Apologies for my previous answer didn't study your question correctly.

As I said, I don't think you can sync the 2 ScrollView

correctly without getting any latency. However, you can still use one view.

It gets a little tricky because you also want to split the split into equal parts with a weight attribute.

The solution can be found here . Based on this, I came up with the following code:

<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>

      

Then, if you want to switch overlapping to left

and right

call:

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

      



and

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

      

after setting the parameters to be redrawn with:

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

      


A working example can be found on this GitHub page .

0


source







All Articles