The interaction of Scrollviews and Recylcerviews in Android

I'm trying to create a calendar with vertical and horizontal scrolling, where, when you scroll vertically by the hours of the day, and when you scroll horizontally, this is by the days of the month. This link contains an almost working file that I need:

Current behavior

If you notice about the last half of the gif, after scrolling vertically, the horizontal scrolling of the body and the title of the day is dsynced, but as soon as you move the list back to the beginning or end, they will synchronize again.

Basically what I have are 2 horizontally scrollable types of recyclers that scroll with each other, as indicated here:

Scrolling Sync Multiple RecyclerViews

Actual implementation:

public class CalendarFragment extends BaseFragment {

@BindView(R.id.dayHeaderView)
RecyclerView dayHeaderView;

@BindView(R.id.dayBodyView)
RecyclerView dayBodyView;

private static final String TAG = CalendarFragment.class.getSimpleName();

private DayHeaderAdapter dayHeaderAdapter = new DayHeaderAdapter();
private DayBodyAdapter dayBodyAdapter = new DayBodyAdapter();

private final RecyclerView.OnScrollListener dayHeaderOSL = new SelfRemovingOnScrollListener() {
    @Override
    public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) {
        super.onScrolled(recyclerView, dx, dy);
        dayBodyView.scrollBy(dx, dy);
        Log.e(TAG, "onScrolled: dayHeader x : " + dx + " y : " + dy );
    }
};
private  final RecyclerView.OnScrollListener dayBodyOSL = new SelfRemovingOnScrollListener() {

    @Override
    public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx, final int dy) {
        super.onScrolled(recyclerView, dx, dy);
        dayHeaderView.scrollBy(dx, dy);
        Log.e(TAG, "onScrolled: function x : " + dx + " y : " + dy );
        Log.e(TAG, "onScrolled: dayHeader x : " + dayHeaderView.getX() + " y : " + dayHeaderView.getY() );
        Log.e(TAG, "onScrolled: dayBody x : " + dayBodyView.getX() + " y : " + dayBodyView.getY() );
    }
};

public CalendarFragment() {}

public static CalendarFragment create(boolean showScheduler) {
    return new CalendarFragment();
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_calendar, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    getComponent().inject(this);
    ButterKnife.bind(this, view);

    LinearLayoutManager llm = new LinearLayoutManager(getContext());
    llm.setOrientation(LinearLayoutManager.HORIZONTAL);

    LinearLayoutManager llm2 = new LinearLayoutManager(getContext());
    llm2.setOrientation(LinearLayoutManager.HORIZONTAL);

    dayHeaderView.setLayoutManager(llm2);
    dayHeaderView.setAdapter(dayHeaderAdapter);
    dayHeaderAdapter.displayHeader();

    dayHeaderView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {

        private int mLastX;

        @Override
        public boolean onInterceptTouchEvent(@NonNull final RecyclerView rv, @NonNull final
        MotionEvent e) {
            Log.d("debug", "Day Header: onInterceptTouchEvent");

            final Boolean ret = rv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE;
            if (!ret) {
                onTouchEvent(rv, e);
            }
            return Boolean.FALSE;
        }

        @Override
        public void onTouchEvent(@NonNull final RecyclerView rv, @NonNull final MotionEvent e) {
            Log.d("debug", "Day Header: onTouchEvent");

            final int action;
            if ((action = e.getAction()) == MotionEvent.ACTION_DOWN && dayBodyView
                    .getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
                mLastX = rv.getScrollX();
                dayBodyView.scrollBy(rv.getScrollX(), rv.getScrollY());
                rv.addOnScrollListener(dayHeaderOSL);
            }
            else {
                if (action == MotionEvent.ACTION_UP && rv.getScrollX() == mLastX) {
                    rv.removeOnScrollListener(dayHeaderOSL);
                }
            }
        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(final boolean disallowIntercept) {
            Log.d("debug", "Day Header: onRequestDisallowInterceptTouchEvent");
        }
    });

    CalenderLayoutManager clm = new CalenderLayoutManager();
    clm.setTotalColumnCount(10);
    dayBodyView.setLayoutManager(llm);
    dayBodyView.setAdapter(dayBodyAdapter);
    dayBodyAdapter.displayBody();

    dayBodyView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {

        private int mLastX;

        @Override
        public boolean onInterceptTouchEvent(@NonNull final RecyclerView rv, @NonNull final
        MotionEvent e) {
            Log.d("debug", "Day Body: onInterceptTouchEvent");

            final Boolean ret = rv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE;
            if (!ret) {
                onTouchEvent(rv, e);
            }
            return Boolean.FALSE;
        }

        @Override
        public void onTouchEvent(@NonNull final RecyclerView rv, @NonNull final MotionEvent e) {
            Log.d("debug", "Day Body: onTouchEvent");

            final int action;
            if ((action = e.getAction()) == MotionEvent.ACTION_DOWN && dayHeaderView
                    .getScrollState
                            () == RecyclerView.SCROLL_STATE_IDLE) {
                mLastX = rv.getScrollX();
                dayHeaderView.scrollBy(rv.getScrollX(), rv.getScrollY());
                rv.addOnScrollListener(dayBodyOSL);
            }
            else {
                if (action == MotionEvent.ACTION_UP && rv.getScrollX() == mLastX) {
                    rv.removeOnScrollListener(dayBodyOSL);
                }
            }
        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(final boolean disallowIntercept) {
            Log.d("debug", "Day Body: onRequestDisallowInterceptTouchEvent");
        }
    });

}


public class SelfRemovingOnScrollListener extends RecyclerView.OnScrollListener {
    @Override
    public final void onScrollStateChanged(@NonNull final RecyclerView recyclerView, final int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            recyclerView.removeOnScrollListener(this);
        }
    }
}
}

, . :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/silver"
android:gravity="center"
android:orientation="vertical">

<LinearLayout 
    android:id="@+id/fillable_area_01"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:splitMotionEvents="false">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <View
            android:layout_width="30dp"
            android:layout_height="40dp"
            android:background="@color/black"/>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/dayHeaderView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none"
        android:splitMotionEvents="false">

        <LinearLayout
            android:id="@+id/fillable_area_02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:splitMotionEvents="false">

            <edu.calendar.ui.HourView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />


            <android.support.v7.widget.RecyclerView
                android:id="@+id/dayBodyView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

        </LinearLayout>
    </ScrollView>
</LinearLayout>

- , dsync scrollview , ? , ? , , , , , !

.

+4

All Articles