Skip to content

Commit a1cee9d

Browse files
committed
Improve sticky header compute
1 parent de1eaf5 commit a1cee9d

File tree

2 files changed

+47
-19
lines changed

2 files changed

+47
-19
lines changed

src/recyclerview/RecyclerViewManager.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,11 @@ export class RecyclerViewManager<T> {
164164
}
165165

166166
tryGetLayout(index: number) {
167-
if (this.layoutManager && this.layoutManager.getLayoutCount() > index) {
167+
if (
168+
this.layoutManager &&
169+
index >= 0 &&
170+
index < this.layoutManager.getLayoutCount()
171+
) {
168172
return this.layoutManager.getLayout(index);
169173
}
170174
return undefined;

src/recyclerview/components/StickyHeaders.tsx

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,24 @@ export const StickyHeaders = <TItem,>({
5858
data,
5959
extraData,
6060
}: StickyHeaderProps<TItem>) => {
61-
const [stickyIndices, setStickyIndices] = useState<{
61+
const [stickyHeaderState, setStickyHeaderState] = useState<{
6262
currentStickyIndex: number;
6363
nextStickyIndex: number;
64-
}>({ currentStickyIndex: -1, nextStickyIndex: -1 });
65-
66-
const { currentStickyIndex, nextStickyIndex } = stickyIndices;
64+
currentStickyHeight: number;
65+
nextStickyY: number;
66+
}>({
67+
currentStickyIndex: -1,
68+
nextStickyIndex: -1,
69+
currentStickyHeight: 0,
70+
nextStickyY: 0,
71+
});
72+
73+
const {
74+
currentStickyIndex,
75+
nextStickyIndex,
76+
nextStickyY,
77+
currentStickyHeight,
78+
} = stickyHeaderState;
6779

6880
// Memoize sorted indices based on their Y positions
6981
const sortedIndices = useMemo(() => {
@@ -79,12 +91,12 @@ export const StickyHeaders = <TItem,>({
7991
if (legthInvalid) {
8092
return;
8193
}
82-
const adjustedValue = recyclerViewManager.getLastScrollOffset();
94+
const adjustedScrollOffset = recyclerViewManager.getLastScrollOffset();
8395

8496
// Binary search for current sticky index
8597
const currentIndexInArray = findCurrentStickyIndex(
8698
sortedIndices,
87-
adjustedValue,
99+
adjustedScrollOffset,
88100
(index) => recyclerViewManager.getLayout(index).y
89101
);
90102

@@ -95,13 +107,23 @@ export const StickyHeaders = <TItem,>({
95107
newNextStickyIndex = -1;
96108
}
97109

110+
const newNextStickyY =
111+
(recyclerViewManager.tryGetLayout(newNextStickyIndex)?.y ?? 0) +
112+
recyclerViewManager.firstItemOffset;
113+
const newCurrentStickyHeight =
114+
recyclerViewManager.tryGetLayout(newStickyIndex)?.height ?? 0;
115+
98116
if (
99117
newStickyIndex !== currentStickyIndex ||
100-
newNextStickyIndex !== nextStickyIndex
118+
newNextStickyIndex !== nextStickyIndex ||
119+
newNextStickyY !== nextStickyY ||
120+
newCurrentStickyHeight !== currentStickyHeight
101121
) {
102-
setStickyIndices({
122+
setStickyHeaderState({
103123
currentStickyIndex: newStickyIndex,
104124
nextStickyIndex: newNextStickyIndex,
125+
nextStickyY: newNextStickyY,
126+
currentStickyHeight: newCurrentStickyHeight,
105127
});
106128
}
107129
}, [
@@ -110,6 +132,8 @@ export const StickyHeaders = <TItem,>({
110132
recyclerViewManager,
111133
sortedIndices,
112134
legthInvalid,
135+
nextStickyY,
136+
currentStickyHeight,
113137
]);
114138

115139
useEffect(() => {
@@ -139,20 +163,20 @@ export const StickyHeaders = <TItem,>({
139163
});
140164
}
141165

142-
const currentLayout = recyclerViewManager.getLayout(currentStickyIndex);
143-
const nextLayout = recyclerViewManager.getLayout(nextStickyIndex);
144-
145-
const pushStartsAt = nextLayout.y - currentLayout.height;
166+
const pushStartsAt = nextStickyY - currentStickyHeight;
146167

147168
return scrollY.interpolate({
148-
inputRange: [
149-
pushStartsAt + recyclerViewManager.firstItemOffset,
150-
nextLayout.y + recyclerViewManager.firstItemOffset,
151-
],
152-
outputRange: [0, -currentLayout.height],
169+
inputRange: [pushStartsAt, nextStickyY],
170+
outputRange: [0, -currentStickyHeight],
153171
extrapolate: "clamp",
154172
});
155-
}, [currentStickyIndex, nextStickyIndex, recyclerViewManager, scrollY]);
173+
}, [
174+
currentStickyHeight,
175+
currentStickyIndex,
176+
nextStickyIndex,
177+
nextStickyY,
178+
scrollY,
179+
]);
156180

157181
// Memoize header content
158182
const headerContent = useMemo(() => {

0 commit comments

Comments
 (0)