diff --git a/examples/common_expo/app/onboarding.tsx b/examples/common_expo/app/onboarding.tsx index 32bf835..868b4c9 100644 --- a/examples/common_expo/app/onboarding.tsx +++ b/examples/common_expo/app/onboarding.tsx @@ -1,5 +1,6 @@ import Animated, { useAnimatedRef, + useAnimatedScrollHandler, useSharedValue, } from 'react-native-reanimated'; import { SafeAreaView, StyleSheet, View } from 'react-native'; @@ -9,6 +10,7 @@ import { OnboardingListItem, OnboardingItem, OnboardingWrapper, + Pagination, } from '@/components/Onboarding'; const items: OnboardingItem[] = [ @@ -18,9 +20,16 @@ const items: OnboardingItem[] = [ ]; export default function Onboarding() { + const offsetX = useSharedValue(0); const flatListIndex = useSharedValue(0); const flatListRef = useAnimatedRef>(); + const handleOnScroll = useAnimatedScrollHandler({ + onScroll: (event) => { + offsetX.value = event.contentOffset.x; + }, + }); + return ( @@ -34,12 +43,14 @@ export default function Onboarding() { onViewableItemsChanged={({ viewableItems }) => { flatListIndex.value = viewableItems[0].index ?? 0; }} + onScroll={handleOnScroll} bounces={false} showsHorizontalScrollIndicator={false} horizontal pagingEnabled /> + ; +}; + +export const Pagination: FC = ({ length, offsetX }) => ( + + {[...Array(length).keys()].map((_, index) => ( + + ))} + +); + +const styles = StyleSheet.create({ + container: { + alignItems: 'center', + flexDirection: 'row', + justifyContent: 'center', + }, +}); diff --git a/examples/common_expo/components/Onboarding/Pagination/PaginationItem.tsx b/examples/common_expo/components/Onboarding/Pagination/PaginationItem.tsx new file mode 100644 index 0000000..b3fd8f3 --- /dev/null +++ b/examples/common_expo/components/Onboarding/Pagination/PaginationItem.tsx @@ -0,0 +1,60 @@ +import { FC } from 'react'; +import { StyleSheet, useWindowDimensions } from 'react-native'; +import Animated, { + Extrapolation, + interpolate, + interpolateColor, + SharedValue, + useAnimatedStyle, +} from 'react-native-reanimated'; + +type PaginationItemProps = { + itemIndex: number; + offsetX: SharedValue; +}; + +export const PaginationItem: FC = ({ + itemIndex, + offsetX, +}) => { + const { width: SCREEN_WIDTH } = useWindowDimensions(); + + const animatedItemStyle = useAnimatedStyle(() => { + const backgroundColor = interpolateColor( + offsetX.value, + [ + (itemIndex - 1) * SCREEN_WIDTH, + itemIndex * SCREEN_WIDTH, + (itemIndex + 1) * SCREEN_WIDTH, + ], + ['#e2e2e2', 'blue', '#e2e2e2'], + ); + + const width = interpolate( + offsetX.value, + [ + (itemIndex - 1) * SCREEN_WIDTH, + itemIndex * SCREEN_WIDTH, + (itemIndex + 1) * SCREEN_WIDTH, + ], + [32, 16, 32], + Extrapolation.CLAMP, + ); + + return { + width, + backgroundColor, + }; + }); + + return ; +}; + +const styles = StyleSheet.create({ + item: { + borderRadius: 5, + height: 10, + marginHorizontal: 4, + width: 32, + }, +}); diff --git a/examples/common_expo/components/Onboarding/Pagination/index.ts b/examples/common_expo/components/Onboarding/Pagination/index.ts new file mode 100644 index 0000000..e016c96 --- /dev/null +++ b/examples/common_expo/components/Onboarding/Pagination/index.ts @@ -0,0 +1 @@ +export * from './Pagination'; diff --git a/examples/common_expo/components/Onboarding/index.ts b/examples/common_expo/components/Onboarding/index.ts index 884e356..2564218 100644 --- a/examples/common_expo/components/Onboarding/index.ts +++ b/examples/common_expo/components/Onboarding/index.ts @@ -1,3 +1,4 @@ export * from './NextButton'; export * from './OnboardingListItem'; export * from './OnboardingWrapper'; +export * from './Pagination';