Reputation: 97
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