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 , ? , ? , , , , , !
.