I have a horizontal recycler-view within motion layout. Sometimes when I do a horizontal swipe, the page starts scrolling in the vertical direction. This happens when we do a diagonal fling.
I want something like Google Play where horizontal recycler-views can defend slightly diagonal vertical swipes. BTW setting nestedscrollEnabled
doesn't work.
There is quite a nice article regarding all the RecycleView scroll behavior and the issue itself. Checkout Rúben Sousa article. Solution is quite easy, try to use adopted RecyclerView:
/**
* A RecyclerView that only handles scroll events with the same orientation of its LayoutManager.
* Avoids situations where nested recyclerviews don't receive touch events properly:
*/
public class OrientationAwareRecyclerView extends RecyclerView {
private float lastX = 0.0f;
private float lastY = 0.0f;
private boolean scrolling = false;
public OrientationAwareRecyclerView(@NonNull Context context) {
this(context, null);
}
public OrientationAwareRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public OrientationAwareRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
addOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
scrolling = newState != RecyclerView.SCROLL_STATE_IDLE;
}
});
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
final LayoutManager lm = getLayoutManager();
if (lm == null) {
return super.onInterceptTouchEvent(e);
}
boolean allowScroll = true;
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
lastX = e.getX();
lastY = e.getY();
// If we were scrolling, stop now by faking a touch release
if (scrolling) {
MotionEvent newEvent = MotionEvent.obtain(e);
newEvent.setAction(MotionEvent.ACTION_UP);
return super.onInterceptTouchEvent(newEvent);
}
break;
}
case MotionEvent.ACTION_MOVE: {
// We're moving, so check if we're trying
// to scroll vertically or horizontally so we don't intercept the wrong event.
float currentX = e.getX();
float currentY = e.getY();
float dx = Math.abs(currentX - lastX);
float dy = Math.abs(currentY - lastY);
allowScroll = dy > dx ? lm.canScrollVertically() : lm.canScrollHorizontally();
break;
}
}
if (!allowScroll) {
return false;
}
return super.onInterceptTouchEvent(e);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With