Chad Bingham
Chad Bingham

Reputation: 33876

CoordinatorLayout with RecyclerView: onScroll

I have a RecyclerView where I have added different actions that can be performed on the list items. Particularly, DragDrop and SwipeDismiss. DragDrop is initiated by long-press, and SwipeDismiss is initiated by swiping. I have to watch for scroll events to block those actions from happening. It is annoying to be scrolling then it suddenly switched to dragging. Before I would add an OnScrollListener to handle this.

This is what I did before:

@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    if(newState == RecyclerView.SCROLL_STATE_IDLE){
        drag.setCurrentAction(IDLE);
    } else {
        drag.setCurrentAction(SCROLL);
    }
}

No longer will work

I recently added CoordinatorLayout for collapsable toolbars. Now when scrolling up, drag wont get set to SCROLL until the toolbar has been collapsed. I tried to create my own behavior, but that would replace my current behavior I am using; @string/appbar_scrolling_view_behavior. This removed the behaviors I wanted for the toolbar and didn't work to notify my drag state.


What I have tried:

@Override
public boolean onStartNestedScroll(CoordinatorLayout cl, CollapsingToolbarLayout child, View directTargetChild,
        View target, int nestedScrollAxes) {

    if (nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL) {
        if (drag.getCurrentAction().ordinal() < SCROLL.ordinal()) {
            /* No actions have started and we are scrolling. set the new action */
            drag.setCurrentAction(SCROLL);
        }
        return true;
    }
    return super.onStartNestedScroll(cl, child, directTargetChild, target, nestedScrollAxes);
}

@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, CollapsingToolbarLayout child, View target) {
    super.onStopNestedScroll(coordinatorLayout, child, target);
    if (drag.getCurrentAction() == SCROLL) {
        drag.setCurrentAction(INVALID);
    }
}

So my question

How do I listen for those scroll changes on my recycler view that are being intercepted by the CoordinatorLayout? Is a Behavior the correct way?

Upvotes: 5

Views: 3398

Answers (2)

Juanan Jimenez
Juanan Jimenez

Reputation: 234

have you tried to add a touchEvent listener, then deactivate the interceptors events for the parent viewgroup holder? I reckon that returns to the child the control of any touch event you want to handle.

    scrollView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
               // Disallow the touch request for parent scroll on touch of child view

                     v.getParent().requestDisallowInterceptTouchEvent(true);

                } else if (event.getAction() == MotionEvent.ACTION_UP) {

                      v.getParent().requestDisallowInterceptTouchEvent(false);
               }
          return false;
          }
       });

Upvotes: 1

ianhanniballake
ianhanniballake

Reputation: 200080

You should instead use ItemTouchHelper as detailed in this blog post.

It contains methods such as

  • onMove(RecyclerView, ViewHolder, ViewHolder)
  • onSwiped(ViewHolder, int)

Which allow you to implement drag and drop as well as swipe to dismiss without writing custom Behaviors or touch event handling.

Upvotes: -1

Related Questions