android view.scrollBy interferes with drag listener events

I am trying to implement scrolling using DragShadowBuilder

but when scrollBy is invoked by my LOCATION drag event, all other drag events are delayed until some time after the view has scrolled

specifically they are delayed anywhere from 1 second to 4 seconds after scrolling has started

if I do not invoke scrollBy then my events are received instantly but my view does not scroll

I tried invoking the scrollBy using ViewCompat.postOnAnimation but that did not make any difference

I also tried invoking it from a seperate thread but that does not make any difference

though I has to use smoothScrollBy instead as scrollBy throws a not UI thread exception

does anyone know how I can get around this responsiveness lag when scrolling?

as my requirements are

  1. my view must be draggable to other views outside of the RecyclerView (and be able to interact with those views)

  2. my view must be able to scroll the recycler view upon being dragged such that its location is at the bottom or top of the recycler view

this is my current code

// based on androidx.recyclerview.widget.ItemTouchHelper source code

int startedX;
int startedY;
ViewHolder mSelected;
ShadowItemTouchHelper itemTouchHelper;
private Rect mTmpRect;
private long mDragScrollStartTimeInMs;
RecyclerView mRecyclerView;
Callback mCallback;
float x;
float y;

final Runnable mScrollRunnable = new Runnable() {
    @Override
    public void run() {
        if (mSelected != null && scrollIfNecessary()) {
            mRecyclerView.removeCallbacks(mScrollRunnable);
            ViewCompat.postOnAnimation(mRecyclerView, this);
        }
    }
};

boolean scrollIfNecessary() {
    if (mSelected == null) {
        mDragScrollStartTimeInMs = Long.MIN_VALUE;
        return false;
    }
    final long now = System.currentTimeMillis();
    RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
    if (mTmpRect == null) {
        mTmpRect = new Rect();
    }
    int scrollX = 0;
    int scrollY = 0;
    lm.calculateItemDecorationsForChild(mSelected.itemView, mTmpRect);
    if (lm.canScrollHorizontally()) {
        int width = mRecyclerView.getMeasuredWidth();
        if (width - x < 200) {
            scrollX = (int) (mSelected.itemView.getWidth() * 0.2);
        } else if (width - x > width - 200) {
            scrollX = (int) (-mSelected.itemView.getWidth() * 0.2);
        }
    }
    if (lm.canScrollVertically()) {
        int height = mRecyclerView.getMeasuredHeight();
        if (height - y < 200) {
            scrollY = (int) (mSelected.itemView.getHeight() * 0.2);
        } else if (height - y > height - 200) {
            scrollY = (int) (-mSelected.itemView.getHeight() * 0.2);
        }
    }
    if (scrollX != 0 || scrollY != 0) {
        if (mDragScrollStartTimeInMs == Long.MIN_VALUE) {
            mDragScrollStartTimeInMs = now;
        }

        // SCROLL
        mRecyclerView.scrollBy(scrollX, scrollY);

        return true;
    }
    mDragScrollStartTimeInMs = Long.MIN_VALUE;
    return false;
}

@Override
public boolean onDrag(View v, DragEvent event) {
    //noinspection unchecked
    Pair<ShadowItemTouchHelper, ViewHolder> data = (Pair<ShadowItemTouchHelper, ViewHolder>) event.getLocalState();

    final int action = event.getAction();
    switch(action) {
        case DragEvent.ACTION_DRAG_STARTED:
            toastList.show(dragStartedKey);
            Log.d(TAG, "onDrag: STARTED");
            itemTouchHelper = data.first;
            mRecyclerView = itemTouchHelper.mRecyclerView;
            mCallback = itemTouchHelper.mCallback;
            mSelected = data.second;
            startedX = mSelected.itemView.getLeft();
            startedY = mSelected.itemView.getTop();
            return true;
        case DragEvent.ACTION_DRAG_ENTERED:
            toastList.show(dragEnteredKey);
            Log.d(TAG, "onDrag: ENTERED");
            mSelected = data.second;
            return true;

        case DragEvent.ACTION_DROP:
            toastList.show(dragDropKey);
            Log.d(TAG, "onDrag: DROP");
            mSelected = null;
            return true;
        case DragEvent.ACTION_DRAG_ENDED:
            toastList.show(dragEndedKey);
            Log.d(TAG, "onDrag: ENDED");
            mSelected = null;
            return true;
        case DragEvent.ACTION_DRAG_EXITED:
            toastList.show(dragExitedKey);
            Log.d(TAG, "onDrag: EXITED");
            mSelected = null;
            return true;

        case DragEvent.ACTION_DRAG_LOCATION:
            x = event.getX();
            y = event.getY();
            mRecyclerView.removeCallbacks(mScrollRunnable);
            mScrollRunnable.run();
            mRecyclerView.invalidate();
            return true;
    }
    return false;
}

Source: Android Questions

LEAVE A COMMENT