-
Notifications
You must be signed in to change notification settings - Fork 414
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(js): add view pager hook (#873)
* feat(js): add view pager hook * fix types * fix(class-exporting): Add Omit type for exclude private methods. * docs: usePager Hook Usage section * fix(readme): Readme update. * fix(readme): Update hook params && README * fix(lint): Fix for lint --------- Co-authored-by: Piotr Trocki <piotr.trocki@callstack.com> Co-authored-by: Vladislav Bataev <bataevvlad@gmail.com> Co-authored-by: gronxb <gron1gh1@gmail.com>
- Loading branch information
1 parent
d26b793
commit 057d8e7
Showing
6 changed files
with
310 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import React, { useMemo } from 'react'; | ||
import { StyleSheet, View, SafeAreaView, Text } from 'react-native'; | ||
|
||
import { LikeCount } from './component/LikeCount'; | ||
import { NavigationPanel } from './component/NavigationPanel'; | ||
import { usePagerView } from 'react-native-pager-view'; | ||
|
||
export function PagerHookExample() { | ||
const { AnimatedPagerView, ref, ...rest } = usePagerView({ pagesAmount: 10 }); | ||
|
||
return ( | ||
<SafeAreaView style={styles.container}> | ||
<AnimatedPagerView | ||
// @ts-ignore | ||
testID="pager-view" | ||
ref={ref} | ||
style={styles.PagerView} | ||
initialPage={0} | ||
layoutDirection="ltr" | ||
overdrag={rest.overdragEnabled} | ||
scrollEnabled={rest.scrollEnabled} | ||
onPageScroll={rest.onPageScroll} | ||
onPageSelected={rest.onPageSelected} | ||
onPageScrollStateChanged={rest.onPageScrollStateChanged} | ||
pageMargin={10} | ||
// Lib does not support dynamically orientation change | ||
orientation="horizontal" | ||
> | ||
{useMemo( | ||
() => | ||
rest.pages.map((_, index) => ( | ||
<View | ||
testID="pager-view-content" | ||
key={index} | ||
style={{ | ||
flex: 1, | ||
backgroundColor: '#fdc08e', | ||
alignItems: 'center', | ||
padding: 20, | ||
}} | ||
collapsable={false} | ||
> | ||
<LikeCount /> | ||
<Text | ||
testID={`pageNumber${index}`} | ||
>{`page number ${index}`}</Text> | ||
</View> | ||
)), | ||
[rest.pages] | ||
)} | ||
</AnimatedPagerView> | ||
{/*@ts-ignore*/} | ||
<NavigationPanel {...rest} /> | ||
</SafeAreaView> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
backgroundColor: 'white', | ||
}, | ||
image: { | ||
width: 300, | ||
height: 200, | ||
padding: 20, | ||
}, | ||
PagerView: { | ||
flex: 1, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import type * as ReactNative from 'react-native'; | ||
import type { | ||
OnPageScrollEventData as PagerViewOnPageScrollEventData, | ||
OnPageSelectedEventData as PagerViewOnPageSelectedEventData, | ||
OnPageScrollStateChangedEventData as PageScrollStateChangedNativeEventData, | ||
} from './specs/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) => { | ||
const lastPageNumber = prevPages[prevPages.length - 1]; | ||
if (lastPageNumber) { | ||
return [...prevPages, lastPageNumber + 1]; | ||
} | ||
return prevPages; | ||
}); | ||
}, []); | ||
|
||
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, | ||
}, | ||
}, | ||
], | ||
{ | ||
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, | ||
overdragEnabled, | ||
setPage, | ||
addPage, | ||
removePage, | ||
toggleScroll, | ||
toggleAnimation, | ||
setProgress, | ||
onPageScroll, | ||
onPageSelected, | ||
onPageScrollStateChanged, | ||
toggleOverdrag, | ||
AnimatedPagerView, | ||
PagerView, | ||
}; | ||
} |