Skip to content

Instantly share code, notes, and snippets.

@PPartisan
Created February 18, 2016 16:25
Show Gist options
  • Save PPartisan/e01fa548a4a723aa45d8 to your computer and use it in GitHub Desktop.
Save PPartisan/e01fa548a4a723aa45d8 to your computer and use it in GitHub Desktop.
RecyclerView that passes touch interactions to child ScrollViews based on the ScrollView's content
public class TouchDelegatingRecyclerView extends RecyclerView {
private static final String TAG = TouchDelegatingRecyclerView.class.getSimpleName();
private static final int UP_SWIPE = 803;
private static final int DOWN_SWIPE = UP_SWIPE + 1;
private float originalY = 0;
private int swipeDirection = 0;
private boolean isIntercepting = false;
public DozingRecyclerView(Context context) {
super(context);
}
public DozingRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DozingRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
final int childCount = getChildCount();
final float x = e.getX();
final float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
originalY = y;
break;
case MotionEvent.ACTION_MOVE:
if (y < originalY) {
swipeDirection = UP_SWIPE;
} else if (y > originalY) {
swipeDirection = DOWN_SWIPE;
}
break;
}
for (int i = 0; i<childCount; i++) {
View child = getChildAt(i);
if (x > child.getLeft() && x < child.getRight() && y > child.getTop() && y < child.getBottom()) {
final TouchDelegatingViewHolder holder = ((TouchDelegatingViewHolder)getChildViewHolder(child));
final TouchDelegatingScrollView scrollView = holder.scrollView;
int status = scrollView.getStatus();
if ((status != TouchDelegatingScrollView.TOP_AND_BOTTOM)
&& ((status != TouchDelegatingScrollView.BOTTOM && swipeDirection == UP_SWIPE)
|| ((status != TouchDelegatingScrollView.TOP && swipeDirection == DOWN_SWIPE)))) {
isIntercepting = true;
return false;
}
}
}
isIntercepting = false;
return super.onInterceptTouchEvent(e);
}
@Override
public boolean onTouchEvent(MotionEvent e) {
return !isIntercepting && super.onTouchEvent(e);
}
}
public class TouchDelegatingScrollView extends ScrollView {
private static final String TAG = TouchDelefatingScrollView.class.getSimpleName();
public static final int TOP = 235;
public static final int BOTTOM = TOP + 1;
public static final int NOWHERE = TOP + 2;
public static final int TOP_AND_BOTTOM = TOP + 3;
private int status = TOP;
public LimitNotifyingScrollView(Context context) {
super(context);
}
public LimitNotifyingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LimitNotifyingScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LimitNotifyingScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
View child = getChildAt(0);
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
int childHeight = child.getMeasuredHeight();
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
status = (childHeight < parentHeight) ? TOP_AND_BOTTOM : TOP;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
View bottomView = getChildAt(getChildCount()-1);
final int bottom = (bottomView.getBottom()-(getHeight() + getScrollY() + bottomView.getTop()));
if (bottom <= 0 && t == 0) {
status = TOP_AND_BOTTOM;
} else if (bottom <= 0) {
status = BOTTOM;
} else if (t == 0) {
status = TOP;
} else {
status = NOWHERE;
}
super.onScrollChanged(l, t, oldl, oldt);
}
public int getStatus() {
return status;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment