react-native-pager-view
Version:
React Native wrapper for Android and iOS ViewPager
149 lines (131 loc) • 3.94 kB
text/typescript
import type * as ReactNative from 'react-native';
import type {
OnPageScrollEventData as PagerViewOnPageScrollEventData,
OnPageSelectedEventData as PagerViewOnPageSelectedEventData,
OnPageScrollStateChangedEventData as PageScrollStateChangedNativeEventData,
} from './PagerViewNativeComponent';
type PageScrollStateChangedNativeEvent =
ReactNative.NativeSyntheticEvent<PageScrollStateChangedNativeEventData>;
import { PagerView } from './PagerView';
import { Animated } from 'react-native';
import { useCallback, useMemo, useRef, useState } from 'react';
export type UsePagerViewProps = ReturnType<typeof usePagerView>;
const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);
type UsePagerViewParams = {
pagesAmount: number;
};
export function usePagerView(
{ pagesAmount }: UsePagerViewParams = { pagesAmount: 0 }
) {
const ref = useRef<PagerView>(null);
const [pages, setPages] = useState<number[]>(
new Array(pagesAmount).fill('').map((_v, index) => index)
);
const [activePage, setActivePage] = useState(0);
const [isAnimated, setIsAnimated] = useState(true);
const [overdragEnabled, setOverdragEnabled] = useState(false);
const [scrollEnabled, setScrollEnabled] = useState(true);
const [scrollState, setScrollState] = useState('idle');
const [progress, setProgress] = useState({ position: 0, offset: 0 });
const onPageScrollOffset = useRef(new Animated.Value(0)).current;
const onPageScrollPosition = useRef(new Animated.Value(0)).current;
const onPageSelectedPosition = useRef(new Animated.Value(0)).current;
const setPage = useCallback(
(page: number) =>
isAnimated
? ref.current?.setPage(page)
: ref.current?.setPageWithoutAnimation(page),
[isAnimated]
);
const addPage = useCallback(() => {
setPages((prevPages) => {
return [...prevPages, prevPages.length];
});
}, []);
const removePage = useCallback(() => {
setPages((prevPages) => {
if (prevPages.length === 1) {
return prevPages;
}
return prevPages.slice(0, prevPages.length - 1);
});
}, []);
const toggleAnimation = useCallback(
() => setIsAnimated((animated) => !animated),
[]
);
const toggleScroll = useCallback(
() => setScrollEnabled((enabled) => !enabled),
[]
);
const toggleOverdrag = useCallback(
() => setOverdragEnabled((enabled) => !enabled),
[]
);
const onPageScroll = useMemo(
() =>
Animated.event<PagerViewOnPageScrollEventData>(
[
{
nativeEvent: {
offset: onPageScrollOffset,
position: onPageScrollPosition,
},
},
],
{
listener: ({ nativeEvent: { offset, position } }) => {
setProgress({
position,
offset,
});
},
useNativeDriver: true,
}
),
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
const onPageSelected = useMemo(
() =>
Animated.event<PagerViewOnPageSelectedEventData>(
[{ nativeEvent: { position: onPageSelectedPosition } }],
{
listener: ({ nativeEvent: { position } }) => {
setActivePage(position);
},
useNativeDriver: true,
}
),
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
const onPageScrollStateChanged = useCallback(
(e: PageScrollStateChangedNativeEvent) => {
setScrollState(e.nativeEvent.pageScrollState);
},
[]
);
return {
ref,
activePage,
isAnimated,
pages,
scrollState,
scrollEnabled,
progress,
overdrag: overdragEnabled,
setPage,
addPage,
removePage,
toggleScroll,
toggleAnimation,
setProgress,
onPageScroll,
onPageSelected,
onPageScrollStateChanged,
toggleOverdrag,
AnimatedPagerView,
PagerView,
};
}