Android: horizontal Recyclerview inside vertical Recycliewiew

This seems like a fairly common model in Android. I am trying to create something similar to how Facebook displays their advertisements:

Facebook Ads

You can see that they have an external vertical recyclerview with an internal horizontal recyclerview as one of the elements of the external vertical recycliewiew adapter.

I followed this guide from Google in the section "Managing events in broadcasts in ViewGroup" - http://developer.android.com/training/gestures/viewgroup.html , since Recyclerview extends ViewGroup and the code there seems to be like what I I want to make.

I set it up a bit so that it detects movements along the Y axis instead of movements along the X axis and applies them to an external vertical recyclerview.

/** * Created by Simon on 10/11/2015. *///This is the recyclerview that would allow all vertical scrolls public class VerticallyScrollRecyclerView extends RecyclerView { public VerticallyScrollRecyclerView(Context context) { super(context); } public VerticallyScrollRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public VerticallyScrollRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } ViewConfiguration vc = ViewConfiguration.get(this.getContext()); private int mTouchSlop = vc.getScaledTouchSlop(); private boolean mIsScrolling; private float startY; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); // Always handle the case of the touch gesture being complete. if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { // Release the scroll. mIsScrolling = false; startY = ev.getY(); return false; // Do not intercept touch event, let the child handle it } switch (action) { case MotionEvent.ACTION_MOVE: { if (mIsScrolling) { // We're currently scrolling, so yes, intercept the // touch event! return true; } // If the user has dragged her finger horizontally more than // the touch slop, start the scroll // left as an exercise for the reader final float yDiff = calculateDistanceY(ev.getY()); Log.e("yDiff ", ""+yDiff); // Touch slop should be calculated using ViewConfiguration // constants. if (yDiff > mTouchSlop) { // Start scrolling! Log.e("Scroll", "we are scrolling vertically"); mIsScrolling = true; return true; } break; } } return false; } private float calculateDistanceY(float endY) { return startY - endY; } } 

My xml layout:

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/main_recyclerview_holder"> <com.example.simon.customshapes.VerticallyScrollRecyclerView android:id="@+id/main_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> 

When I try to drag an internal horizontal recyclerview (hoping that the touchhevent will be intercepted by an external vertical recyclerview), the external recyclerview will not scroll vertically at all.

It also gives me an error message:

Scrolling error handling; pointer index for id -1 not found. Have you missed any MotionEvents?

Does anyone know how to do this correctly?

+5
source share
1 answer

I had a similar problem and did not find any solution on the Internet. In my application, I have a list of user-interactive elements that you can interact with by scrolling horizontally (in which case, scrolling should be blocked), but when scrolling vertically, it should scroll. According to your comments, you have already solved your problem, but for those whose problem is similar to mine and whose research led them here, I will publish my solution. I'm a little under the hood of a RecyclerView , and here's what I found. "Scrolling processing error, pointer index for id -1 not found. Did any MotionEvents actions skip?" - The problem is that the mScrollPointerId variable, which is used to get index , is set to onTouchEvent when ACTION_DOWN occurs. In my particular case, when ACTION_DOWN occurs, I return false from onInterceptTouchEvent , since at this moment I do not know that the weather user wants to scroll or interact with the list item. And in this case, onTouchEvent not called. Later, when I find out that the user wants to interact with the element, I return false from onInterceptTouchEvent and call onTouchEvent , but it cannot handle scrolling because mScrollPointerId not set. The solution here is to call onTouchEvent from onInterceptTouchEvent when ACTION_DOWN happens.

 @Override public boolean onInterceptTouchEvent(MotionEvent e) { ... switch (action) { case MotionEvent.ACTION_DOWN: { onTouchEvent(e); ... break; } ... } ... } 
0
source

Source: https://habr.com/ru/post/1234215/


All Articles