Nested RecyclerView. How to prevent parent RecyclerView from getting scrolled while child RecyclerView is scrolling?

前端 未结 14 1387
余生分开走
余生分开走 2020-12-07 21:24

I am trying to implement a horizontal recyclerview and each item of the recyclerview will be a vertical recyclerview with a grid layou

14条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-07 21:42

    I fixed this issue in a similar project by taking the opposite approach to you (and everyone else here).

    Rather than allow the child to tell the parent when to stop looking at events, I let the parent decide when to ignore (based on direction). This approach requires a custom view though which can be a little more work. Below is what I created which would be used as the Outer/Parent view.

    public class DirectionalRecyclerView extends RecyclerView {
    
        private static float LOCK_DIRECTION_THRESHOLD; //The slop
        private float startX;
        private float startY;
        private LockDirection mLockDirection = null;
    
        public DirectionalRecyclerView(Context context) {
            super(context);
            findThreshold(context);
        }
    
        public DirectionalRecyclerView(Context context, AttributeSet attrs) {
            super(context, attrs);
            findThreshold(context)
        }
    
        public DirectionalRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            findThreshold(context);
        }
    
        private void findThreshold(Context context) {
            //last number is number of dp to move before deciding that's a direction not a tap, you might want to tweak it
            LOCK_DIRECTION_THRESHOLD = context.getResources().getDisplayMetrics().density * 12;
        }
    
        //events start at the top of the tree and then pass down to
        //each child view until they reach where they were initiated
        //unless the parent (this) method returns true for this visitor
        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    startX = event.getX();
                    startY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mLockDirection == null) {
                        float currentX = event.getX();
                        float currentY = event.getY();
                        float diffX = Math.abs(currentX - startX);
                        float diffY = Math.abs(currentY - startY);
                        if (diffX > LOCK_DIRECTION_THRESHOLD) {
                            mLockDirection = LockDirection.HORIZONTAL;
                        } else if (diffY > LOCK_DIRECTION_THRESHOLD) {
                            mLockDirection = LockDirection.VERTICAL;
                        }
                    } else {
                        //we have locked a direction, check whether we intercept
                        //the future touches in this event chain
                        //(returning true steals children's events, otherwise we'll
                        // just let the event trickle down to the child as usual)
                        return mLockDirection == LockDirection.HORIZONTAL;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    mLockDirection = null;
                    break;
            }
            //dispatch cancel, clicks etc. normally
            return super.onInterceptTouchEvent(event);
        }
    
        private enum LockDirection {
            HORIZONTAL,
            VERTICAL
        }
    
    }
    

提交回复
热议问题