Skip to content

Commit 8b5dd8c

Browse files
committed
[feat] Add reanimated scroll view
1 parent 5a2129d commit 8b5dd8c

File tree

4 files changed

+582
-41
lines changed

4 files changed

+582
-41
lines changed

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,13 @@
6767
"react": "18.2.0",
6868
"react-native": "0.73.4",
6969
"react-native-builder-bob": "^0.20.0",
70+
"react-native-reanimated": "^3.17.5",
7071
"typescript": "^5.5.4"
7172
},
7273
"peerDependencies": {
7374
"react": "*",
74-
"react-native": "*"
75+
"react-native": "*",
76+
"react-native-reanimated": "*"
7577
},
7678
"workspaces": [
7779
"example"
@@ -130,4 +132,4 @@
130132
"directories": {
131133
"example": "example"
132134
}
133-
}
135+
}

src/responsive-grid/index.tsx

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
/* eslint-disable react-native/no-inline-styles */
33

44
import React, { useEffect, useMemo, useRef, useState } from 'react';
5-
import { ScrollView, View } from 'react-native';
5+
import { View } from 'react-native';
66
import type { ResponsiveGridProps, TileItem } from './types';
77
import { calcResponsiveGrid } from './calc-responsive-grid';
88
import type { NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
99
import useThrottle from '../hooks/use-throttle';
10+
import Animated, { useAnimatedScrollHandler } from 'react-native-reanimated';
1011
import { renderPropComponent } from '../libs/render-prop-component';
1112

1213
export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
@@ -84,45 +85,41 @@ export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
8485
scrollEventInterval
8586
);
8687

87-
const throttledOnScroll = useThrottle(
88-
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
89-
const currentScrollY = event.nativeEvent.contentOffset.y;
90-
scrollYPosition.current = currentScrollY;
91-
92-
// Calculate the position to check against the threshold
93-
const contentHeight = gridViewHeight;
94-
const scrollViewHeight = containerSize.height;
95-
const threshold = onEndReachedThreshold * scrollViewHeight;
96-
97-
// Check if we've reached the threshold for calling onEndReached
98-
if (
99-
!onEndReachedCalled.current &&
100-
currentScrollY + scrollViewHeight + threshold >= contentHeight
101-
) {
102-
onEndReachedCalled.current = true; // Marked as called to prevent subsequent calls
103-
onEndReached?.(); // call the onEndReached function if it exists
104-
}
105-
106-
// Reset the flag when scrolled away from the bottom
107-
if (currentScrollY + scrollViewHeight + threshold * 2 < contentHeight) {
108-
onEndReachedCalled.current = false;
109-
}
110-
111-
// Update visible items for virtualization
112-
if (virtualization) {
113-
throttledUpdateVisibleItems();
114-
}
115-
},
116-
32
117-
);
88+
const throttledOnScroll = useThrottle((currentScrollY: number) => {
89+
scrollYPosition.current = currentScrollY;
90+
91+
// Calculate the position to check against the threshold
92+
const contentHeight = gridViewHeight;
93+
const scrollViewHeight = containerSize.height;
94+
const threshold = onEndReachedThreshold * scrollViewHeight;
95+
96+
// Check if we've reached the threshold for calling onEndReached
97+
if (
98+
!onEndReachedCalled.current &&
99+
currentScrollY + scrollViewHeight + threshold >= contentHeight
100+
) {
101+
onEndReachedCalled.current = true; // Marked as called to prevent subsequent calls
102+
onEndReached?.(); // call the onEndReached function if it exists
103+
}
104+
105+
// Reset the flag when scrolled away from the bottom
106+
if (currentScrollY + scrollViewHeight + threshold * 2 < contentHeight) {
107+
onEndReachedCalled.current = false;
108+
}
118109

119-
const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
110+
// Update visible items for virtualization
111+
if (virtualization) {
112+
throttledUpdateVisibleItems();
113+
}
114+
}, 32);
115+
116+
const onScroll = useAnimatedScrollHandler((event) => {
120117
if (onScrollProp) {
121118
onScrollProp(event);
122119
}
123120

124-
throttledOnScroll(event);
125-
};
121+
throttledOnScroll(event.contentOffset.y);
122+
});
126123

127124
useEffect(() => {
128125
if (virtualization) {
@@ -155,7 +152,7 @@ export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
155152
setContainerSize({ width, height });
156153
}}
157154
>
158-
<ScrollView
155+
<Animated.ScrollView
159156
onScroll={onScroll}
160157
contentContainerStyle={{
161158
height: sumScrollViewHeight || '100%',
@@ -195,7 +192,7 @@ export const ResponsiveGrid: React.FC<ResponsiveGridProps> = ({
195192
>
196193
{renderPropComponent(FooterComponent)}
197194
</View>
198-
</ScrollView>
195+
</Animated.ScrollView>
199196
</View>
200197
);
201198
};

src/responsive-grid/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type React from 'react';
22
import type { ReactNode } from 'react';
3-
import type { NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle } from 'react-native';
3+
import type { StyleProp, ViewStyle } from 'react-native';
4+
import type { ReanimatedScrollEvent } from 'react-native-reanimated/lib/typescript/hook/commonTypes';
45

56
interface RenderItemProps {
67
item: any;
@@ -50,7 +51,7 @@ export interface ResponsiveGridProps {
5051
itemUnitHeight?: number;
5152

5253
/** Callback function triggered when the scroll view is scrolled. */
53-
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
54+
onScroll?: (event: ReanimatedScrollEvent) => void;
5455

5556
/** Callback function triggered when the scroll reaches near the end of the scrollable grid. */
5657
onEndReached?: () => void;

0 commit comments

Comments
 (0)