react-native-draggable-flatlist icon indicating copy to clipboard operation
react-native-draggable-flatlist copied to clipboard

Scroll Bug in NestableScrollContainer

Open CharlesZim opened this issue 2 years ago • 7 comments

This package has external dependencies of react-native-reanimated and react-native-gesture-handler which must be installed separately. Before opening an issue related to animations or gestures please verify that you have completed ALL installation steps, including the changes to MainActivity.

Describe the bug When using NestableScrollContainer with react-native-draggable-flatlist, I noticed that if I try to scroll in a different direction while a scroll motion is still ongoing, it works fine. However, if I wait for the scroll to complete and then attempt to scroll again, depending on the gesture, it often fails to scroll.

To Reproduce This issue can be reproduced in the official Snack: "https://snack.expo.dev/@computerjazz/draggable-flatlist-examples". Navigate to the "Nested" Screen. Try scrolling up and, before the scroll completes, scroll down (or vice versa). It works as expected. However, if you wait for the scroll to complete and then attempt to scroll again, you will encounter the issue.

Platform & Dependencies Please list any applicable dependencies in addition to those below (react-navigation etc).

  • react-native-draggable-flatlist version: 4.0.1
  • Platform: iOS
  • React Native or Expo version: 0.72.3
  • Reanimated version: 3.4.2
  • React Native Gesture Handler version: 2.12.1

Additional context I have also tried replacing NestableDraggableFlatList with a regular FlatList, and it worked without issues. This leads me to believe that the problem might be specific to NestableDraggableFlatList.

CharlesZim avatar Aug 14 '23 11:08 CharlesZim

+1

zekicanAYDIN avatar Sep 04 '23 08:09 zekicanAYDIN

I am having the same issue. The frequency of the bug seems do decrease as the value of the activationDistance prop increases

Samad198 avatar Dec 04 '23 12:12 Samad198

This seems to be caused by the ScrollView conflicting with the GestureDetector component that DraggableFlatList is using internally. Removing the gesture detector fixes the scroll issue (but breaks everything else obviously)

This issue in the react-native-gesture-handler repo seems relevant. I haven't found a workaround yet but will update here if I do.

CarterSimonson avatar Jan 28 '24 00:01 CarterSimonson

I was able to find a workaround -> https://github.com/CarterSimonson/react-native-draggable-flatlist/pull/1

Here's what I ended up doing:

  • Update the PanHandler in DraggableFlatList to utilize an enabled state.
  • Compose a simultaneous tapGesture that replaces the "drag" handler returned to list items
    • Set the shared enabled state to true when the tapGesture is pressed down.
    • Reset enabled to false on press up.

I initially tried controlling the enabled state from within the drag function but was getting some gnarly race conditions.

This results in the following behavior:

  • If the user attempts to drag without triggering the tapGesture, the panGesture will fail and allow the regular scroll event.
  • If the user drags on the tappable area (the drag icon for me in this case), the tapGesture will fire simultaneously and set the enabled state to true. The panGesture will activate and track the pan events.

This works but unfortunately required a breaking change to the API.

Demo:

https://github.com/computerjazz/react-native-draggable-flatlist/assets/31598368/479c7be2-ee7c-42cc-8741-851cfcc56608

CarterSimonson avatar Feb 06 '24 04:02 CarterSimonson

Hi @CarterSimonson could you provide some of the code of how you got this working? It doesn't seem your PR fixed this issue by default or I think I'd be seeing my issue resolved unless I need to update react-native-gesture-handler library to the latest. Only solution I've found to this is increasing activationDistance by a gross amount and lowering it when dragging item

SethCram avatar Aug 21 '24 02:08 SethCram

Hey @SethCram,

My goal was to only allow the elements to be dragged when a button on each of them was clicked and dragged: image

Here's a code snippet of the workaround from my component that wraps this drag button on each of my list items. The only change to the way the library is used is that a tapGesture from RN gesture handler is passed as an argument to renderItem. The drag event will not begin unless the tapGesture is fired first, which prevented the scrolling bug in my case.

import { GestureDetector } from 'react-native-gesture-handler';

// Part of the workaround is that a `tapGesture` is now passed as an argument of the renderItem function:
function renderItem({ item, getIndex, tapGesture }: RenderItemParams<KeyedString>) {
  const index = getIndex();

  // The dragging logic will only begin if this tapGesture is fired beforehand
  const right = (
    <GestureDetector gesture={tapGesture}>
      <DragIcon />
    </GestureDetector>
  );

  if (index !== undefined) {
    return (
      <InputListItem
        value={item.value}
        onChangeText={(value) => updateIngredient(value, index)}
        onBlur={() => onBlur(index)}
        right={right}
      />
    );
  }
}
return <NestableDraggableFlatList
  data={ingredients}
  onDragEnd={({ data }) => onChange(data)}
  keyExtractor={(value) => value.id}
  renderItem={renderItem}
/>

One limitation of this is that it doesn't prevent the scrolling bug if the entire list item is a clickable area (like it is in this demo). It takes advantage of the fact that I only needed to support drag events on a small section of each list item.

Hopefully that clears some things up, I am happy to elaborate further if not 😄

CarterSimonson avatar Aug 21 '24 02:08 CarterSimonson