package com.github.tibolte.agendacalendarview.calendar.weekslist;
import com.github.tibolte.agendacalendarview.utils.BusProvider;
import com.github.tibolte.agendacalendarview.utils.Events;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
public class WeekListView extends RecyclerView {
private boolean mUserScrolling = false;
private boolean mScrolling = false;
// region Constructors
public WeekListView(Context context) {
super(context);
}
public WeekListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WeekListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// endregion
// region Public methods
/**
* Enable snapping behaviour for this recyclerView
*
* @param enabled enable or disable the snapping behaviour
*/
public void setSnapEnabled(boolean enabled) {
if (enabled) {
addOnScrollListener(mScrollListener);
} else {
removeOnScrollListener(mScrollListener);
}
}
// endregion
// region Private methods
private OnScrollListener mScrollListener = new OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
final WeeksAdapter weeksAdapter = (WeeksAdapter) getAdapter();
switch (newState) {
case SCROLL_STATE_IDLE:
if (mUserScrolling) {
scrollToView(getCenterView());
postDelayed(() -> weeksAdapter.setDragging(false), 700); // Wait for recyclerView to settle
}
mUserScrolling = false;
mScrolling = false;
break;
// If scroll is caused by a touch (scroll touch, not any touch)
case SCROLL_STATE_DRAGGING:
BusProvider.getInstance().send(new Events.CalendarScrolledEvent());
// If scroll was initiated already, this is not a user scrolling, but probably a tap, else set userScrolling
if (!mScrolling) {
mUserScrolling = true;
}
weeksAdapter.setDragging(true);
break;
case SCROLL_STATE_SETTLING:
// The user's finger is not touching the list anymore, no need
// for any alpha animation then
weeksAdapter.setAlphaSet(true);
mScrolling = true;
break;
}
}
};
private View getChildClosestToPosition(int y) {
if (getChildCount() <= 0) {
return null;
}
int itemHeight = getChildAt(0).getMeasuredHeight();
int closestY = 9999;
View closestChild = null;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
int childCenterY = ((int) child.getY() + (itemHeight / 2));
int yDistance = childCenterY - y;
// If child center is closer than previous closest, set it as closest
if (Math.abs(yDistance) < Math.abs(closestY)) {
closestY = yDistance;
closestChild = child;
}
}
return closestChild;
}
private View getCenterView() {
return getChildClosestToPosition(getMeasuredHeight() / 2);
}
private void scrollToView(View child) {
if (child == null) {
return;
}
stopScroll();
int scrollDistance = getScrollDistance(child);
if (scrollDistance != 0) {
smoothScrollBy(0, scrollDistance);
}
}
private int getScrollDistance(View child) {
int itemHeight = getChildAt(0).getMeasuredHeight();
int centerY = getMeasuredHeight() / 2;
int childCenterY = ((int) child.getY() + (itemHeight / 2));
return childCenterY - centerY;
}
// endregion
}