Skip to content

Commit a088626

Browse files
authored
fix: Entering layout animation flickering (#509)
## Description Flickering was caused by the animated style assigned on the same view as the entering layout animation. Unfortunately, the two shouldn't be mixed. I moved the overridden cell dimensions to the outer view to keep the inner `Animated.View` having only entering and exiting animations. ## Example recordings | Before | After | |-|-| | <video src="https://github.com/user-attachments/assets/19a4b330-5adc-4e89-b351-cbd7386162d9" /> | <video src="https://github.com/user-attachments/assets/dd569d13-7552-498a-a92b-eb9879856706" /> |
1 parent 0fc582c commit a088626

File tree

4 files changed

+22
-33
lines changed

4 files changed

+22
-33
lines changed

packages/react-native-sortables/src/components/shared/DraggableView/ItemCell.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,30 @@ export default function ItemCell({
4242
layoutStyleValue,
4343
onLayout
4444
}: ItemCellProps) {
45-
const { controlledItemDimensionsStyle } = useCommonValuesContext();
45+
const { overriddenCellDimensions } = useCommonValuesContext();
4646

4747
const decorationStyleValue = useItemDecoration(
4848
itemKey,
4949
isActive,
5050
activationAnimationProgress
5151
);
5252

53-
const animatedStyle = useAnimatedStyle(() => {
54-
return {
55-
...decorationStyleValue.value,
56-
...layoutStyleValue.value,
57-
transform: [
58-
...((layoutStyleValue.value.transform ?? []) as TransformsArray),
59-
...((decorationStyleValue.value.transform ?? []) as TransformsArray)
60-
]
61-
};
62-
});
53+
const animatedCellStyle = useAnimatedStyle(() => ({
54+
...overriddenCellDimensions.value,
55+
...decorationStyleValue.value,
56+
...layoutStyleValue.value,
57+
transform: [
58+
...((layoutStyleValue.value.transform ?? []) as TransformsArray),
59+
...((decorationStyleValue.value.transform ?? []) as TransformsArray)
60+
]
61+
}));
6362

6463
return (
65-
<Animated.View style={[baseStyle, styles.decoration, animatedStyle]}>
64+
<Animated.View style={[baseStyle, styles.decoration, animatedCellStyle]}>
6665
<AnimatedOnLayoutView
6766
entering={entering}
6867
exiting={exiting}
69-
style={[controlledItemDimensionsStyle, hidden && styles.hidden]}
68+
style={hidden && styles.hidden}
7069
onLayout={onLayout}>
7170
{children}
7271
</AnimatedOnLayoutView>

packages/react-native-sortables/src/providers/grid/GridLayoutProvider/GridLayoutProvider.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const { GridLayoutProvider, useGridLayoutContext } = createProvider(
5757
itemHeights,
5858
itemPositions,
5959
itemWidths,
60+
overriddenCellDimensions,
6061
shouldAnimateLayout
6162
} = useCommonValuesContext();
6263
const { applyControlledContainerDimensions } = useMeasurementsContext();
@@ -134,6 +135,7 @@ const { GridLayoutProvider, useGridLayoutContext } = createProvider(
134135

135136
if (isVertical) {
136137
itemWidths.value = value;
138+
overriddenCellDimensions.value = { width: value + mainGap.value };
137139
} else {
138140
itemHeights.value = value;
139141
}

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

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import { type PropsWithChildren, useEffect, useMemo } from 'react';
2-
import type { View, ViewStyle } from 'react-native';
3-
import {
4-
useAnimatedRef,
5-
useAnimatedStyle,
6-
useDerivedValue
7-
} from 'react-native-reanimated';
2+
import type { View } from 'react-native';
3+
import { useAnimatedRef, useDerivedValue } from 'react-native-reanimated';
84

5+
import { EMPTY_OBJECT } from '../../constants';
96
import type { Animatable } from '../../integrations/reanimated';
107
import {
118
useAnimatableValue,
@@ -87,16 +84,8 @@ const { CommonValuesContext, CommonValuesProvider, useCommonValuesContext } =
8784
controlledItemDimensions.height ? null : {}
8885
);
8986
const activeItemDimensions = useMutableValue<Dimensions | null>(null);
90-
const controlledItemWidth = useDerivedValue(() =>
91-
typeof itemWidths.value === 'number' ? itemWidths.value : undefined
92-
);
93-
const controlledItemHeight = useDerivedValue(() =>
94-
typeof itemHeights.value === 'number' ? itemHeights.value : undefined
95-
);
96-
const controlledItemDimensionsStyle = useAnimatedStyle<ViewStyle>(() => ({
97-
height: controlledItemHeight.value,
98-
width: controlledItemWidth.value
99-
}));
87+
const overriddenCellDimensions =
88+
useMutableValue<Partial<Dimensions>>(EMPTY_OBJECT);
10089

10190
// DRAG STATE
10291
const activeItemKey = useMutableValue<null | string>(null);
@@ -167,7 +156,6 @@ const { CommonValuesContext, CommonValuesProvider, useCommonValuesContext } =
167156
containerWidth,
168157
controlledContainerDimensions,
169158
controlledItemDimensions,
170-
controlledItemDimensionsStyle,
171159
customHandle,
172160
dragActivationDelay,
173161
dragActivationFailOffset,
@@ -182,6 +170,7 @@ const { CommonValuesContext, CommonValuesProvider, useCommonValuesContext } =
182170
itemsLayoutTransitionMode,
183171
itemWidths,
184172
keyToIndex,
173+
overriddenCellDimensions,
185174
prevActiveItemKey,
186175
shouldAnimateLayout,
187176
snapOffsetX,

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import type { ReactNode } from 'react';
2-
import type { ScrollView, View, ViewStyle } from 'react-native';
2+
import type { ScrollView, View } from 'react-native';
33
import type {
44
GestureTouchEvent,
55
GestureType
66
} from 'react-native-gesture-handler';
77
import type {
88
AnimatedRef,
9-
AnimatedStyle,
109
MeasuredDimensions,
1110
SharedValue
1211
} from 'react-native-reanimated';
@@ -79,8 +78,8 @@ export type CommonValuesContextType =
7978
containerHeight: SharedValue<null | number>;
8079
itemWidths: SharedValue<ItemSizes>;
8180
itemHeights: SharedValue<ItemSizes>;
81+
overriddenCellDimensions: SharedValue<Partial<Dimensions>>;
8282
activeItemDimensions: SharedValue<Dimensions | null>;
83-
controlledItemDimensionsStyle: AnimatedStyle<ViewStyle>;
8483

8584
// DRAG STATE
8685
prevActiveItemKey: SharedValue<null | string>;

0 commit comments

Comments
 (0)