Skip to content

Instantly share code, notes, and snippets.

@drewandre
Last active December 30, 2022 08:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save drewandre/6ef76e1c8a9328db496d6aba8d60a9a3 to your computer and use it in GitHub Desktop.
Save drewandre/6ef76e1c8a9328db496d6aba8d60a9a3 to your computer and use it in GitHub Desktop.
Pagination component for use with react-native-snap-carousel
import React from 'react'
import { StyleSheet } from 'react-native'
import Animated, {
Extrapolate,
interpolate,
useAnimatedStyle
} from 'react-native-reanimated'
import { colors, metrics } from 'styles';
function clamp(value, lowerBound, upperBound) {
'worklet'
return Math.min(Math.max(lowerBound, value), upperBound);
};
const DEFAULT_SIZE = 15
function AnimatedDot({
index,
style,
progress,
multiplier,
scaleDots
}) {
const animatedStyles = useAnimatedStyle(() => {
const opacity = interpolate(
clamp(progress.value, 0, 1 - multiplier),
[
(index * multiplier) - multiplier,
index * multiplier,
(index * multiplier) + multiplier
],
[0.25, 1, 0.25],
Extrapolate.CLAMP
)
return {
opacity,
transform: [
{
scale: scaleDots
? interpolate(
opacity,
[0.25, 1],
[0.5, 1]
)
: 1
}
]
}
})
return (
<Animated.View
key={`onboarding-pagination-dot-${index}`}
style={[style, animatedStyles]}
/>
)
}
export function Pagination({
progress,
numberOfPages,
scaleDots = false,
dotStyles = {},
containerStyles = {},
size = 'medium'
}) {
const multiplier = 1 / numberOfPages
function returnSize() {
switch (size) {
case 'small':
return {
width: DEFAULT_SIZE * 0.6,
height: DEFAULT_SIZE * 0.6,
}
case 'large':
return {
width: DEFAULT_SIZE * 1.2,
height: DEFAULT_SIZE * 1.2,
}
default:
return {
width: DEFAULT_SIZE,
height: DEFAULT_SIZE,
}
}
}
function renderDots() {
let dots = []
for (let i = 0; i < numberOfPages; i++) {
dots.push(
<AnimatedDot
key={`pagination-${i}`}
index={i}
scaleDots={scaleDots}
multiplier={multiplier}
progress={progress}
size={size}
style={[
styles.dotStyle,
dotStyles,
returnSize()
]}
/>
)
}
return dots
}
return (
<View style={[
styles.dotContainer,
containerStyles,
]}>
{renderDots()}
</View>
)
}
const styles = StyleSheet.create({
dotContainer: {
flex: 1,
paddingHorizontal: metrics.padding,
flexDirection: 'row',
alignSelf: 'center'
},
dotStyle: {
width: DEFAULT_SIZE,
height: DEFAULT_SIZE,
borderRadius: 50,
marginHorizontal: 5,
backgroundColor: colors.white,
},
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment