Skip to content

Commit 6427c8d

Browse files
authored
fix: Multi touch flickering issue (#392)
## Description This PR fixes multi touch flickering issue caused by the `handleDragEnd` being called on the cancelled gesture. The second touch gesture was properly ignored and failed but it called `handleDragEnd` as this method is always called in the `onFinalize` callback, which invalidated not only the second gesture that we wanted to ignore, but also the first one that was correct and should be still handled. The behavior on Android is unfortunately not perfect, because when we start touching a second item, the gesture on the first one gets invalidated as the `onTouchesUp` callback is not properly called on the gesture instance. This is a `react-native-gesture-handler` issue that I reported here: software-mansion/react-native-gesture-handler#3543
1 parent 1601090 commit 6427c8d

2 files changed

Lines changed: 33 additions & 25 deletions

File tree

packages/react-native-sortables/src/constants/platform.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ import { version as reactVersion } from 'react';
22
import { Platform } from 'react-native';
33

44
export const IS_WEB = Platform.OS === 'web';
5+
export const IS_ANDROID = Platform.OS === 'android';
56

67
export const IS_REACT_19 = reactVersion.startsWith('19.');

packages/react-native-sortables/src/providers/shared/DragProvider.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -456,47 +456,54 @@ const { DragProvider, useDragContext } = createProvider('Drag')<
456456
const handleDragEnd = useCallback(
457457
(key: string, activationAnimationProgress: SharedValue<number>) => {
458458
'worklet';
459+
if (activeItemKey.value && activeItemKey.value !== key) {
460+
return;
461+
}
462+
463+
clearAnimatedTimeout(activationTimeoutId.value);
459464
touchStartTouch.value = null;
460465
currentTouch.value = null;
461-
dragStartItemTouchOffset.value = null;
462-
dragStartTouchPosition.value = null;
463-
activeItemPosition.value = null;
464-
activeItemDimensions.value = null;
465-
touchPosition.value = null;
466466
activationState.value = DragActivationState.INACTIVE;
467-
updateStartScrollOffset?.(null);
467+
468+
if (activeItemKey.value === null) {
469+
return;
470+
}
468471

469472
if (activeHandleMeasurements) {
470473
activeHandleMeasurements.value = null;
471474
}
472475

473-
const fromIndex = dragStartIndex.value;
474-
const toIndex = keyToIndex.value[key]!;
475-
476-
if (activeItemKey.value !== null) {
477-
prevActiveItemKey.value = activeItemKey.value;
478-
activeItemKey.value = null;
479-
updateLayer?.(LayerState.INTERMEDIATE);
480-
haptics.medium();
481-
482-
stableOnDragEnd({
483-
fromIndex,
484-
indexToKey: indexToKey.value,
485-
key,
486-
keyToIndex: keyToIndex.value,
487-
toIndex
488-
});
489-
}
476+
prevActiveItemKey.value = activeItemKey.value;
477+
dragStartItemTouchOffset.value = null;
478+
dragStartTouchPosition.value = null;
479+
activeItemPosition.value = null;
480+
activeItemDimensions.value = null;
481+
touchPosition.value = null;
482+
activeItemKey.value = null;
483+
dragStartIndex.value = -1;
490484

491485
const animate = (callback?: (finished: boolean | undefined) => void) =>
492486
withTiming(0, { duration: dropAnimationDuration.value }, callback);
493487

494-
dragStartIndex.value = -1;
495488
activationAnimationProgress.value = animate();
496489
inactiveAnimationProgress.value = animate();
497490
activeAnimationProgress.value = animate();
498491

499-
clearAnimatedTimeout(activationTimeoutId.value);
492+
updateStartScrollOffset?.(null);
493+
updateLayer?.(LayerState.INTERMEDIATE);
494+
haptics.medium();
495+
496+
const fromIndex = dragStartIndex.value;
497+
const toIndex = keyToIndex.value[key]!;
498+
499+
stableOnDragEnd({
500+
fromIndex,
501+
indexToKey: indexToKey.value,
502+
key,
503+
keyToIndex: keyToIndex.value,
504+
toIndex
505+
});
506+
500507
activationTimeoutId.value = setAnimatedTimeout(() => {
501508
prevActiveItemKey.value = null;
502509
activeItemDropped.value = true;

0 commit comments

Comments
 (0)