konradns
konradns

Reputation: 97

Cannot scroll inside NestableDraggableFlatList

I'm struggling couple days with resolve issue which my client found. I'm not able to scroll inside of the Draggable FlatList. It's annoying because user can create many subtask which finally is on entire screen and unable to scroll down or to top.

You can see that in the video here: https://drive.google.com/file/d/1ZrPFyQJNoeorsLyXgHY9obQYSvasyxCr/view

What's funny, it was working fine in 3.1.2 but I upgraded React Native version to the latest and need to upgrade reanimated and as well react-native-draggable-flatlist to 4.0.1.

other dependency libs are:

"react-native-reanimated": "3.6.2",
"react-native-gesture-handler": "2.15.0", 
 

implementation is pretty standard I think:

  const renderItem = ({ item, drag, isActive }: RenderItemParams<SubTaskItemModel>) => (
    <>
      <SubTaskItem
        key={item.id}
        selected={item.taskDone}
        doneTime={item.taskDoneTime ? new Date(item.taskDoneTime) : undefined}
        doneBy={
          item.taskDoneBy
            ? teamMembers.find((user) => user.id === item.taskDoneBy)?.attributes.name
            : undefined
        }
        onSelectedChange={onSelectedChange(item)}
        value={item.value}
        onChangeValue={onChangeValue(item)}
        focus={item.focus}
        onNext={onNext(item)}
        onDelete={onDelete(item)}
        onBlur={onBlur(item)}
        drag={drag}
        isActive={isActive}
        editMode={editMode}
        addingMode={addingMode}
      />
      <Separator />
    </>
  );

  return (
      <NestableScrollContainer>
        <NestableDraggableFlatList
          data={state}
          keyExtractor={(item) => String(item.id)}
          renderItem={renderItem}
          activationDistance={1}
          onDragEnd={({ data }) => {
          dispatch(SetTasksState(data));
          onOrderTasks && onOrderTasks(data);
          }}
        />
      {editMode && showAddButton && <SubTaskItem button onClick={() => dispatch(AddNewTask())} />}
    </NestableScrollContainer>
  );

SubTaskItem

function SubTaskItem({
  editMode,
  addingMode,
  button,
  onClick,
  onDelete,
  focus,
  selected,
  onSelectedChange,
  value,
  onChangeValue,
  onNext,
  onBlur,
  drag,
  doneTime,
  doneBy,
  isActive,
}: SubTaskItemProps) {
  const { t } = useTranslation();
  const textInputRef = useRef(null);

  useEffect(() => {
    if (focus) {
      (textInputRef.current as any).focus();
    }
  }, [focus]);

  const deleteOnBackspace = useCallback(
    ({ nativeEvent }) => {
      if (nativeEvent?.key === 'Backspace' && value?.length === 0) {
        onDelete && onDelete();
      }
    },
    [value, onDelete]
  );

  const renderDeleteAction = (x: number, progress: Animated.AnimatedInterpolation<number>) => {
    const trans = progress.interpolate({
      inputRange: [0, 1],
      outputRange: [x, 0],
    });

    return (
      <Animated.View style={{ flex: 1, transform: [{ translateX: trans }] }}>
        <DeleteButton onPress={onDelete}>
          <Icon icon={faTrashCan} size="medium" color={themeColors.subtasks.deleteIcon} />
        </DeleteButton>
      </Animated.View>
    );
  };

  const renderRightActions = (
    progress: Animated.AnimatedInterpolation<number>,
    _dragAnimatedValue: Animated.AnimatedInterpolation<number>
  ) => <RightActionContainer>{renderDeleteAction(64, progress)}</RightActionContainer>;

  if (button) {
    return (
      <Button onPress={onClick}>
        <RadioButtonContainer>
          <RadioButton disabled />
        </RadioButtonContainer>
        <Txt type={TxtType.paragraph} style={{ color: themeColors.task.subTasks.addNew }}>
          {t('Task.Subtasks.addNew')}
        </Txt>
      </Button>
    );
  }
  const swipeable = (
    <Swipeable
      friction={2}
      rightThreshold={editMode ? 60 : 0}
      renderRightActions={editMode && renderRightActions}
    >
      <Container>
        <RadioButtonContainer>
          <RadioButton
            selected={selected}
            disabled={!editMode || addingMode}
            onSelect={onSelectedChange}
          />
        </RadioButtonContainer>
        <SubtaskTextContainer>
          <TextInput
            ref={textInputRef}
            onChangeText={(text) => onChangeValue?.(text)}
            onBlur={onBlur}
            value={value}
            editable={editMode && !selected}
            returnKeyType="next"
            onSubmitEditing={onNext}
            enablesReturnKeyAutomatically
            onKeyPress={deleteOnBackspace}
          />
          {selected && doneBy && doneTime && (
            <SubtaskDoneDescription>
              {t('Task.Subtasks.doneBy', {
                author: doneBy,
                date: `${doneTime?.toLocaleString('default', {
                  month: 'short',
                })} ${doneTime?.getDate()}`,
              })}
            </SubtaskDoneDescription>
          )}
        </SubtaskTextContainer>
        {editMode && (
          <TouchableOpacity onLongPress={drag} disabled={isActive}>
            <Icon icon={faBars} size="medium" color={themeColors.subtasks.moveIcon} />
          </TouchableOpacity>
        )}
      </Container>
    </Swipeable>
  );

  return <ScaleDecorator activeScale={1.04}>{swipeable}</ScaleDecorator>;
}

and the main View:

<GestureHandlerRootView testID="EditTaskView-screen">
    <NavigationHeader
        iconLeft={faClipboardCheck as IconProp}
        title="Task.title"
        onClose={onGoBack}
        actionSheetOptions={editTaskOptions}
    />
    <Content // styled-component -> scrollView
        ref={scrollViewRef}
        contentContainerStyle={{ paddingBottom: 30 }}
        keyboardShouldPersistTaps="handled"
    >
        <Tile>
            <TaskHeader
                editable
                hasAccess={canUserMakeChanges}
                name={title}
                onChange={setTitle}
                save={save}
            />
        </Tile>

        <Subtasks
            editMode={canUserMakeChanges}
            key={sectionId}
            initialValues={subTasks}
            onChangeTaskText={onChangeTaskText}
            onChangeTaskCheckmark={onChangeTaskCheckmark}
            onOrderTasks={onOrderTasks}
            onDeleteTask={onDeleteTask}
            scrollView={scrollViewRef}
        />
</Content>
</GestureHandlerRootView>

Upvotes: 1

Views: 189

Answers (0)

Related Questions