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

Not able to scroll if using DraggleFlatlist inside DraggleFlatlist .

Open pankaj210891 opened this issue 3 years ago • 15 comments

        <DraggableFlatList
          nestedScrollEnabled={false}
          data={listDataSource}
          extraData={listDataSource}
          onDragBegin={() => isActive.setValue(1)}
          onRelease={() => isActive.setValue(0)}
          keyExtractor={(item, index) => `draggable-item-${item.id}`}
          // keyExtractor={(item, index) => item.id.toString()}
          renderItem={renderItem}
          onDragEnd={({data}) => setListDataSource(data)}
        />

const renderItem = ({item, index, drag, isActive}) => { return ( <ExpandableComponent drag={drag} isActive={isActive} scale={isActive ? animState.position : 1} dataSource={listDataSource} key={index} isEdit={getEditAndSort} parentIndex={index} setCreateVisibility={setCreateVisibility} setEditableMenuData={setEditableMenuData} setCategoryActiveStatus={(status, index) => { setCategoryActiveStatus(toInt(status), index); }} setMenuItemActiveStatus={(status, parentIndex, index) => { setMenuItemActiveStatus(toInt(status), parentIndex, index); }} onClickFunction={() => { updateLayout(index); }} setChildDataToMainList={(listData, parentIndex) => { //console.log(setChildDataToMainList ${parentIndex});

      let tempArray = [...listDataSource];

      tempArray[parentIndex].menu_items = listData;

      setListDataSource(tempArray);
    }}
    item={item}
  />
);

};

const ExpandableComponent = ({ dataSource, item, onClickFunction, isEdit, drag, scale, isActive, parentIndex, setChildDataToMainList, setCategoryActiveStatus, setMenuItemActiveStatus, setEditableMenuData, setCreateVisibility, }) => { //Custom Component for the Expandable List const [layoutHeight, setLayoutHeight] = useState(0);

const {t, i18n} = useTranslation();

useEffect(() => { if (item.is_expandable) { setLayoutHeight(null); } else { setLayoutHeight(0); } }, [item.is_expandable]);

// console.log(dataSource scale = ${key} );

var isActiveChild = new Animated.Value(0); var clock = new Clock(); var animConfig = { damping: 20, mass: 0.4, stiffness: 100, overshootClamping: false, restSpeedThreshold: 0.2, restDisplacementThreshold: 0.2, toValue: new Value(0), }; var animState = { finished: new Value(0), velocity: new Value(0), position: new Value(1), time: new Value(0), };

const renderItemChild = ({item, index, drag, isActive}) => { var scale = isActive ? animState.position : 1; // var scale = isActive ? new Value(0.9) : 1;

//  console.log(`renderItemChild scale ${scale}`);

return (
  <Animated.View
    style={{
      justifyContent: 'center',
      alignItems: 'center',
      width: '100%',
      elevation: isActive ? 10 : 0,
      shadowRadius: isActive ? 10 : 0,
      shadowColor: isActive ? 'black' : 'transparent',
      shadowOpacity: isActive ? 0.25 : 0,
      transform: [
        {scaleY: isActive ? (Platform.OS === 'web' ? 1.5 : 1.2) : 1},
      ],
    }}>
    <TouchableOpacity
      onPress={() => {
        if (!isEdit) {
          var menuCategoriesIds = item.menu_category_ids;
          let filteredData = dataSource.filter((categoryObj) => {
            return menuCategoriesIds.find(
              (categoryId) => categoryId === categoryObj.id,
            );
          });

          item.selectedCategories = JSON.parse(
            JSON.stringify(filteredData),
          );

          // setEditableData(item);
          // setEdit(true);
          var body = {
            isEdit: true,
            editableData: item,
          };
          setEditableMenuData(body);
          // EventBus.publish(Constants.events.OPEN_CREATE_MODAL, true);
          setCreateVisibility(true);

          // debouncedSendEditData(body);
        }
      }}
      style={[
        styles.content,
        {
          alignSelf: 'center',
          // width: isActive ? '90%' : '100%',
          width: '100%',
          backgroundColor: !item.is_active
            ? Color.DEACTIVATED_COLOR
            : Color.DARK_GREY_LIST_HEADER,
        },
      ]}>
      <View
        style={{
          justifyContent: 'space-between',
          flexDirection: 'row',
          width:
            Platform.OS === 'web'
              ? isEdit
                ? '95%'
                : '100%'
              : isEdit
              ? '85%'
              : '100%',
          alignItems: 'stretch',
        }}>
        <View
          style={{
            flexDirection: 'row',
            paddingVertical: 16,
          }}>
          <Text
            style={[
              styles.skuText,
              {
                opacity: 1,
                color: !item.is_active
                  ? '#3D3D3D'
                  : Color.CUSTOMER_DETAILS_HEADER,
              },
            ]}
            numberOfLines={1}>
            {/* {item.sku ? `[${item.sku}]` : null} */}
            {item.sku
              ? `${
                  String(item.sku).length > 5
                    ? `[${String(item.sku).substr(0, 5)}...]`
                    : `[${item.sku}]`
                }`
              : null}
          </Text>
          <Text
            style={[
              styles.text,
              {
                opacity: 1,
                color: !item.is_active ? '#3D3D3D' : '#F2F2F2',
              },
            ]}>
            {item.name}
          </Text>
        </View>
        <View
          style={{
            flexDirection: 'row',
            justifyContent: 'center',
            alignItems: 'center',
          }}>
          <View
            style={{
              flexDirection: 'row',
              marginHorizontal: isEdit ? 15 : 20,
            }}>
            {!item.is_active ? (
              <Text style={styles.txtDeactivated}>
                {t('DeactivatedKey')}
              </Text>
            ) : null}

            <Text
              style={[
                styles.txtPrice,
                {
                  opacity: 0.9,
                  color: !item.is_active ? '#3D3D3D' : '#F2F2F2',
                },
              ]}>
              {/* {item.price} */}

              {item.price === null
                ? GetFormattedCurrency(
                    Number(item.menu_item_sizes[0].price),
                    GERMAN_COUN_CODE,
                    GERMAN_CURR,
                  )
                : GetFormattedCurrency(
                    Number(item.price),
                    GERMAN_COUN_CODE,
                    GERMAN_CURR,
                  )}

              {/* {item.price !== null ? ' €' : ''} */}
            </Text>
          </View>
        </View>
      </View>

      {isEdit ? (
        <View
          style={{
            width: Platform.OS === 'web' ? '5%' : isEdit ? '15%' : '0%',
            flexDirection: 'row',
            justifyContent: 'space-between',
            alignItems: 'stretch',
          }}>
          <View
            style={{
              justifyContent: 'center',
              alignItems: 'center',
            }}>
            <TouchableOpacity
              onPressIn={() => {
                // console.log('onLongPress');
                drag();
                if (Platform.OS == 'ios') {
                  PusherUtil.playVibration();
                } else {
                  Vibration.vibrate();
                }
              }}
              style={{
                width: 35,
                height: 35,
                alignSelf: 'center',
                justifyContent: 'center',
                alignItems: 'center',
              }}>
              <Icon
                name={'reorder-three-outline'}
                size={30}
                color={'#CAD0D5'}
              />
            </TouchableOpacity>
          </View>

          <TouchableOpacity
            onPress={() => {
              setMenuItemActiveStatus(!item.is_active, parentIndex, index);
            }}
            style={{
              width: 30,
              height: 30,
              backgroundColor: Color.WHITE,
              justifyContent: 'center',
              alignItems: 'center',
            }}>
            <Icon
              name={item.is_active ? 'remove-outline' : 'add-outline'}
              size={25}
              color={Color.BLACK}
            />
          </TouchableOpacity>
        </View>
      ) : null}
    </TouchableOpacity>
  </Animated.View>
);

};

return ( <Animated.View key={item.id} style={{ width: '100%', flexDirection: 'column', transform: [ {scaleY: isActive ? (Platform.OS === 'web' ? 1.5 : 1.2) : 1}, ], }}> {/Header of the Expandable List Item/} <TouchableOpacity onPress={onClickFunction} style={[ styles.content, { width: '100%', backgroundColor: item.color_code ? item.color_code : '#1C8D17', }, ]}> <Animated.Text style={[ styles.headerText, { fontSize: isActive ? 20 : 16, paddingVertical: 16, width: Platform.OS === 'web' ? isEdit ? '95%' : '100%' : isEdit ? '65%' : '75%', }, ]}> {item.name} </Animated.Text> <View style={{ flexDirection: 'row', justifyContent: 'center', paddingHorizontal: 10, alignItems: 'center', }}> <Icon name={ item.is_expandable ? 'chevron-up-outline' : 'chevron-down-outline' } size={30} style={{alignSelf: 'center', marginHorizontal: 10}} color={Color.WHITE} /> {/* </TouchableOpacity> */} </View> {isEdit ? ( <View style={{ width: Platform.OS === 'web' ? '5%' : isEdit ? '15%' : '0%', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'stretch', }}> <View style={{ justifyContent: 'center', alignItems: 'center', }}> <TouchableOpacity onPressIn={() => { drag(); if (Platform.OS == 'ios') { PusherUtil.playVibration(); } else { Vibration.vibrate(); } }} style={{ width: 35, height: 35, alignSelf: 'center', justifyContent: 'center', alignItems: 'center', }}> <Icon name={'reorder-three-outline'} size={30} color={'#CAD0D5'} /> </TouchableOpacity> </View>

        <TouchableOpacity
          onPress={() => {
            setCategoryActiveStatus(!item.is_active, parentIndex);
          }}
          style={{
            width: 30,
            height: 30,
            backgroundColor: Color.WHITE,
            justifyContent: 'center',
            alignItems: 'center',
          }}>
          <Icon
            name={item.is_active ? 'remove-outline' : 'add-outline'}
            size={25}
            color={Color.BLACK}
          />
        </TouchableOpacity>
      </View>
    ) : null}
  </TouchableOpacity>
  <View
    style={{
      height: layoutHeight,
      overflow: 'hidden',
      marginBottom: 10,
    }}>
    {/*Content under the header of the Expandable List Item*/}

    <DraggableFlatList
      nestedScrollEnabled={true}
      data={item.menu_items}
      extraData={item.menu_items}
      keyExtractor={(item, index) => item.id.toString()}
      renderItem={renderItemChild}
      onDragEnd={({data}) => setChildDataToMainList(data, parentIndex)}
    />
  </View>
</Animated.View>

); };

As you can see I have a DraggableFlatList which has list of data with structure like categories and categories has list of items. List of item are also in DraggableFlatList.

When I click on category name list expand. We can drag and drop both by category and items inside a category.

Now the issue is when I expand a category I can drag and drop the item but not able to scroll the list. For more understanding a video of problem is attached.

Also, I am passing 19 item but DraggableFlatList show only 10 some times and some time all.

https://user-images.githubusercontent.com/22121472/119064119-41afcb80-b9f8-11eb-83ed-25ba521183aa.mp4

Any help appreciated.

pankaj210891 avatar May 21 '21 00:05 pankaj210891

hm, you probably need to add simultaneousHandlers. I'm not sure if you can do this with what is currently exposed.

computerjazz avatar May 21 '21 19:05 computerjazz

hm, you probably need to add simultaneousHandlers. I'm not sure if you can do this with what is currently exposed.

I tried to add simultaneousHandlers, but it didn't worked or may be I didn't used it properly.

If possible can you share a example with DraggleFlatList inside DraggleFlatList with simultaneousHandlers.

pankaj210891 avatar May 22 '21 09:05 pankaj210891

@computerjazz Thanks for the great lib. I solved my issue with your simultaneousHandlers and activationDistance. Once again thanks.

pankaj210891 avatar May 23 '21 05:05 pankaj210891

With activationDistance i am able to scroll but now drag and drop is not working for inside draggableflatlist. @computerjazz Please help.

pankaj210891 avatar May 23 '21 06:05 pankaj210891

@pankaj210891 could you please add an example to demonstrate how to solve this issue? I am stuck with the same thing...

matanrokach-honeybook avatar May 24 '21 07:05 matanrokach-honeybook

@matanrokach-honeybook I've fixed a problem with scrolling like this:

Add a activationDistance const to check state. const [activationDistance, setActivationDistance] = useState(100);

Add a scrollEnabled prop for parent scrollview. <ScrollView style={{flex: 1}} scrollEnabled={activationDistance !== 0}>

Set activeDistance prop

<DraggableFlatList
   ...
   activationDistance={activationDistance}
   ...
</DraggableFlatList>

setActivationDistance hook I've used on onDragEnd function and long-press element

For me, it is working fine.

Skr1pt1k avatar May 24 '21 12:05 Skr1pt1k

@pankaj210891 could you please add an example to demonstrate how to solve this issue? I am stuck with the same thing...

I managed to solve this issue...with dragHitSlop={{vertical:isDragBegin ? 0 :-100}} OnDragBegin={()=>{ SetDragBegin(true)}}

OnDragEnd={()=>{ SetDragEnd(false)}}

If you need anymore help, please let me know.

pankaj210891 avatar May 24 '21 15:05 pankaj210891

i have the same issue with Horizontal DraggleFlatlist inside DraggleFlatlist

Donhv avatar Jun 09 '21 15:06 Donhv

@matanrokach-honeybook I've fixed a problem with scrolling like this:

Add a activationDistance const to check state. const [activationDistance, setActivationDistance] = useState(100);

Add a scrollEnabled prop for parent scrollview. <ScrollView style={{flex: 1}} scrollEnabled={activationDistance !== 0}>

Set activeDistance prop

<DraggableFlatList
   ...
   activationDistance={activationDistance}
   ...
</DraggableFlatList>

setActivationDistance hook I've used on onDragEnd function and long-press element

For me, it is working fine.

worked for me, thanks!

pxmage avatar Feb 16 '22 10:02 pxmage

@Skr1pt1k @pxmage Demo Please. I have the same problem.

xclidongbo avatar Jul 04 '22 02:07 xclidongbo

` const renderItem = ({ item, drag, isActive }) => { return ( <ScaleDecorator key={item.id}> <TouchableOpacity activeOpacity={1} onLongPress={drag} disabled={isActive} style={[ styles.item, { backgroundColor: isActive ? "red" : "#fff" }, ]} > <View style={styles.card}> <View style={styles.cardHeader}> <Text style={styles.title}>{item.name}</Text> </View> <NestableScrollContainer> <NestableDraggableFlatList data={data2} extraData={data2} onDragEnd={({ data, from, to }) => setData2(data)} keyExtractor={item => item.id} renderItem={renderItem2} /> </NestableScrollContainer> </View> </TouchableOpacity> </ScaleDecorator> ) };

     <DraggableFlatList
            data={data.filter(item => item.closed === false)}
            extraData={data}
            horizontal
            onDragEnd={({ data, from, to }) => setDtata(data)}
            keyExtractor={item => item.id}
            renderItem={renderItem}
        />

`

Draggable items inside NestableDraggableFlatList don't work.

IsmetGlumcevic avatar Jul 21 '22 04:07 IsmetGlumcevic

Bump, any solutions?

The one mentioned by @Skr1pt1k was the closest (achieving both draggability and scrollability), but it still doesn't fully solve the problem for me... While the list now scrolls properly, it doesn't allow dragging of items on the first long press, only after releasing the finger and reclicking on the item now drags it properly. (Sorry for the poor description, it's a super weird behaviour, let me know if anyone wants a video demonstration)

Edit: We ended up redesigning the feature to use two separate lists instead of having them nested inside one another.

Strengthless avatar Jul 28 '23 09:07 Strengthless

@Strengthless I'm facing the same issue when using NestableDraggableFlatList inside NestableDraggableFlatList

trungledangAxonActive avatar Sep 27 '23 07:09 trungledangAxonActive

I have to use activationDistance for the children NestableDraggableFlatList to make the Parent NestableDraggableFlatList draggable but doing this will make the item in children NestableDraggableFlatList not draggable anymore

trungledangAxonActive avatar Sep 27 '23 07:09 trungledangAxonActive