Track pager drag gesture in a worklet

This commit is contained in:
Dan Abramov
2024-11-26 22:04:31 +00:00
parent 6acbe15f54
commit dc89c75e18
+40 -3
View File
@@ -4,6 +4,11 @@ import PagerView, {
PagerViewOnPageSelectedEvent, PagerViewOnPageSelectedEvent,
PageScrollStateChangedNativeEvent, PageScrollStateChangedNativeEvent,
} from 'react-native-pager-view' } from 'react-native-pager-view'
import Animated, {
useEvent,
useHandler,
useSharedValue,
} from 'react-native-reanimated'
import {atoms as a, native} from '#/alf' import {atoms as a, native} from '#/alf'
@@ -29,6 +34,9 @@ interface Props {
) => void ) => void
testID?: string testID?: string
} }
const AnimatedPagerView = Animated.createAnimatedComponent(PagerView)
export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>( export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
function PagerImpl( function PagerImpl(
{ {
@@ -43,6 +51,7 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
) { ) {
const [selectedPage, setSelectedPage] = React.useState(0) const [selectedPage, setSelectedPage] = React.useState(0)
const pagerView = React.useRef<PagerView>(null) const pagerView = React.useRef<PagerView>(null)
const dragProgress = useSharedValue(selectedPage)
React.useImperativeHandle(ref, () => ({ React.useImperativeHandle(ref, () => ({
setPage: (index: number) => { setPage: (index: number) => {
@@ -72,21 +81,49 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
[pagerView], [pagerView],
) )
const handlePageScroll = usePageScrollHandler(
{
onPageScroll(e: any) {
'worklet'
const progress = e.offset + e.position
dragProgress.value = progress
},
},
[],
)
return ( return (
<View testID={testID} style={[a.flex_1, native(a.overflow_hidden)]}> <View testID={testID} style={[a.flex_1, native(a.overflow_hidden)]}>
{renderTabBar({ {renderTabBar({
selectedPage, selectedPage,
onSelect: onTabBarSelect, onSelect: onTabBarSelect,
})} })}
<PagerView <AnimatedPagerView
ref={pagerView} ref={pagerView}
style={[a.flex_1]} style={[a.flex_1]}
initialPage={initialPage} initialPage={initialPage}
onPageScrollStateChanged={handlePageScrollStateChanged} onPageScrollStateChanged={handlePageScrollStateChanged}
onPageSelected={onPageSelectedInner}> onPageSelected={onPageSelectedInner}
onPageScroll={handlePageScroll}>
{children} {children}
</PagerView> </AnimatedPagerView>
</View> </View>
) )
}, },
) )
function usePageScrollHandler(handlers: any, dependencies: any): any {
const {context, doDependenciesDiffer} = useHandler(handlers, dependencies)
const subscribeForEvents = ['onPageScroll']
const {onPageScroll} = handlers
return useEvent(
event => {
'worklet'
if (event.eventName.endsWith('onPageScroll')) {
onPageScroll?.(event, context)
}
},
subscribeForEvents,
doDependenciesDiffer,
)
}