From d53c0e548ffc56513e58501427161efd9235ab5e Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 27 Aug 2025 20:46:11 -0500 Subject: [PATCH] Add onScrolledDownChange --- src/components/List/index.tsx | 17 +++++++++++++++++ src/view/screens/StorybookLists/index.tsx | 5 ++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/List/index.tsx b/src/components/List/index.tsx index 16ced38363..c5e55da795 100644 --- a/src/components/List/index.tsx +++ b/src/components/List/index.tsx @@ -7,7 +7,9 @@ import { } from 'react-native' import Animated, { type FlatListPropsWithLayout, + runOnJS, useAnimatedScrollHandler, + useSharedValue, } from 'react-native-reanimated' import {useLightbox} from '#/state/lightbox' @@ -40,6 +42,11 @@ type ListProps = Omit, 'contentOffset'> & { * footers. Also applies insets to the scroll indicators. */ footerOffset?: number + /** + * Configures the point at which `onScrolledDownChange` is called. + */ + didScrollDownThreshold?: number + onScrolledDownChange?: (isScrolledDown: boolean) => void } export const List = forwardRef(function List( @@ -48,10 +55,20 @@ export const List = forwardRef(function List( ) { const t = useTheme() const {activeLightbox} = useLightbox() + const isScrolledDown = useSharedValue(false) const scrollHandlers = useListScrollContext() const onScroll = useAnimatedScrollHandler({ onScroll(e, ctx) { scrollHandlers.onScroll?.(e, ctx) + + const didScrollDown = + e.contentOffset.y > (props.didScrollDownThreshold ?? 200) + if (isScrolledDown.get() !== didScrollDown) { + isScrolledDown.set(didScrollDown) + if (props.onScrolledDownChange) { + runOnJS(props.onScrolledDownChange)(didScrollDown) + } + } }, onBeginDrag(e, ctx) { scrollHandlers.onScrollBeginDrag?.(e, ctx) diff --git a/src/view/screens/StorybookLists/index.tsx b/src/view/screens/StorybookLists/index.tsx index 7a4385cf56..347d6e6d62 100644 --- a/src/view/screens/StorybookLists/index.tsx +++ b/src/view/screens/StorybookLists/index.tsx @@ -38,7 +38,7 @@ const log = (msg: any) => console.log(msg) export function Inner() { const onScrollWorklet = useListScrollHandler(e => { 'worklet' - runOnJS(log)(`Scroll Y: ${e.contentOffset.y}`) + runOnJS(log)(`scroll ${e.contentOffset.y}`) }, []) return ( @@ -48,6 +48,9 @@ export function Inner() { data={items} headerOffset={100} footerOffset={100} + onScrolledDownChange={scrolledDown => { + console.log(`Scrolled down: ${scrolledDown}`) + }} renderItem={({item}) => ( {item.title}