On this page
IntroductionPrerequisitesStep 1: Setting Up ConstantsStep 2: Creating the Button ComponentButton ComponentExplanation:Step 3: Creating the Pagination DotsDot ComponentExplanation:Step 4: Adding a Pagination IndicatorPaginationIndicator ComponentExplanation:Step 5: Assembling the Pagination ComponentPagination ComponentExplanation:Step 6: Building the Main Onboarding FlowOnboarding ComponentExplanation:Step 7: Integrating the Onboarding Component into a ScreenExplanation:ConclusionIn this tutorial, we will walk through how to build an animated onboarding flow using React Native Reanimated. We'll break down each component used for pagination, buttons, and dot indicators, and explore the animations involved. By the end of this guide, you'll have a smooth, interactive onboarding experience ready to be implemented in your React Native app.
Watch the tutorialIntroduction
An onboarding flow is a crucial part of any mobile app. It introduces users to the core features and helps them get started quickly. To make this process more engaging, adding subtle animations can enhance the experience. In this tutorial, we will build a multi-step onboarding flow with animated pagination and navigation buttons using Reanimated.
Grab the codeloading...
Prerequisites
Before getting started, ensure you have React Native Reanimated set up in your project. If you're new to it, follow their installation guide for instructions.
Now, let’s dive into creating an animated onboarding experience.
Step 1: Setting Up Constants
First, we’ll define some constants that control spacing, dot size, and animation properties. These will ensure a consistent layout across all components.
1const _spacing = 8;2const _buttonHeight = 42;3const _layoutTransition = LinearTransition.springify()4 .damping(80)5 .stiffness(200);6const _dotContainer = 24;7const _dotSize = _dotContainer / 3;8const _activeDot = "#fff";9const _inactiveDot = "#aaa";1011
_spacing
: General spacing between elements._buttonHeight
: Height of the onboarding navigation buttons._layoutTransition
: A spring-based layout transition that provides smooth movement._dotContainer
: Size of the dot container._dotSize
: Actual size of the dot._activeDot
and_inactiveDot
: Colors for active and inactive dots.
These constants will be used throughout the tutorial to standardize the layout and animations.
Step 2: Creating the Button Component
The Button
component will be used for navigation between the onboarding steps. We'll use Reanimated's AnimatedPressable
to create a button with animated enter and exit effects.
Button Component
1function Button({ children, style, ...rest }: AnimatedProps<PressableProps>) {2 return (3 <AnimatedPressable4 style={[5 {6 height: _buttonHeight,7 borderRadius: _buttonHeight / 2,8 justifyContent: "center",9 alignItems: "center",10 paddingHorizontal: _spacing * 2,11 },12 style,13 ]}14 entering={FadeInLeft.springify().damping(80).stiffness(200)}15 exiting={FadeOutLeft.springify().damping(80).stiffness(200)}16 layout={_layoutTransition}17 {...rest}18 >19 {children}20 </AnimatedPressable>21 );22}2324
Explanation:
- Layout and Style: We give the button a round shape by setting the
borderRadius
to half of its height. It also has padding for spacing. - Animations: When the button appears, it enters with a
FadeInLeft
animation, and when it disappears, it exits with aFadeOutLeft
animation. Both use spring-like physics to ensure smooth transitions.
Step 3: Creating the Pagination Dots
Next, we’ll create animated dots for the pagination. The dots will change color based on the current onboarding step.
Dot Component
1function Dot({ index, animation }: { index: number; animation: SharedValue<number>; }) {2 const stylez = useAnimatedStyle(() => {3 return {4 backgroundColor: interpolateColor(5 animation.value,6 [index - 1, index, index + 1],7 [_inactiveDot, _activeDot, _activeDot]8 ),9 };10 });1112 return (13 <View style={{ width: _dotContainer, height: _dotContainer, justifyContent: "center", alignItems: "center" }}>14 <Animated.View style={[stylez, { width: _dotSize, height: _dotSize, borderRadius: _dotSize }]} />15 </View>16 );17}1819
Explanation:
- interpolateColor: This function interpolates the background color based on the current index, changing the dot color to
_activeDot
(white) when selected and_inactiveDot
(gray) when inactive. - useAnimatedStyle: We use Reanimated's
useAnimatedStyle
to dynamically change the dot's color during the transition between steps.
Step 4: Adding a Pagination Indicator
The PaginationIndicator
is a moving element that highlights the active dot. It grows and shrinks as the user navigates through the onboarding steps.
PaginationIndicator Component
1function PaginationIndicator({ animation }: { animation: SharedValue<number>; }) {2 const stylez = useAnimatedStyle(() => {3 return {4 width: _dotContainer + _dotContainer * animation.value,5 };6 });78 return (9 <Animated.View10 style={[11 {12 backgroundColor: "#29BE56",13 height: _dotContainer,14 width: _dotContainer,15 borderRadius: _dotContainer,16 position: "absolute",17 left: 0,18 top: 0,19 },20 stylez,21 ]}22 />23 );24}2526
Explanation:
- useAnimatedStyle: The width of the indicator is animated as the user switches between onboarding steps. This gives a fluid sliding effect over the dots.
- Layout: The indicator has a fixed position and moves between the dots.
Step 5: Assembling the Pagination Component
Now, let’s bring the Dot
and PaginationIndicator
components together into a Pagination
component. This component will render the dots and control the active step.
Pagination Component
1export function Pagination({ selectedIndex, total }: { selectedIndex: number; total: number; }) {2 const animation = useDerivedValue(() => {3 return withSpring(selectedIndex, { damping: 80, stiffness: 200 });4 });56 return (7 <View style={{ justifyContent: "center", alignItems: "center" }}>8 <View style={{ flexDirection: "row" }}>9 <PaginationIndicator animation={animation} />10 {[...Array(total).keys()].map((i) => (11 <Dot key={`dot-${i}`} index={i} animation={animation} />12 ))}13 </View>14 </View>15 );16}1718
Explanation:
- selectedIndex: The
selectedIndex
determines the current step, which controls the dot color and indicator animation. - useDerivedValue: We use
useDerivedValue
to smoothly animate the transitions between steps with a spring effect. - Rendering Dots: The dots are rendered dynamically based on the total number of steps in the onboarding flow.
Step 6: Building the Main Onboarding Flow
Finally, we’ll put everything together into the main Onboarding
component, which manages the steps, pagination, and buttons for navigating through the onboarding flow.
Onboarding Component
1export function Onboarding({ total, selectedIndex, onIndexChange }: { total: number; selectedIndex: number; onIndexChange: (index: number) => void; }) {2 return (3 <View style={{ padding: _spacing, gap: _spacing * 2 }}>4 <Pagination total={total} selectedIndex={selectedIndex} />5 <View style={{ flexDirection: "row", gap: _spacing }}>6 {selectedIndex > 0 && (7 <Button8 style={{ backgroundColor: "#ddd" }}9 onPress={() => { onIndexChange(selectedIndex - 1); }}10 >11 <Text style={{ fontWeight: "700" }}>Back</Text>12 </Button>13 )}14 <Button15 style={{ backgroundColor: "#036BFB", flex: 1 }}16 onPress={() => {17 if (selectedIndex >= total - 1) return;18 onIndexChange(selectedIndex + 1);19 }}20 >21 {selectedIndex === total - 1 ? (22 <Animated.Text23 key="finish"24 style={{ color: "#fff", fontWeight: "700" }}25 entering={FadeInDown.springify().damping(80).stiffness(200)}26 exiting={FadeOutUp.springify().damping(80).stiffness(200)}27 >28 Finish29 </Animated.Text>30 ) : (31 <Animated.Text32 key="continue"33 style={{ color: "#fff", fontWeight: "700" }}34 layout={_layoutTransition}35 entering={FadeInDown.springify().damping(80).stiffness(200)}36 exiting={FadeOutUp.springify().damping(80).stiffness(200)}37 >38 Continue39 </Animated.Text>40 )}41 </Button>42 </View>43 </View>44 );45}4647
Explanation:
- Buttons: If the
selectedIndex
is greater than 0, the “Back” button appears, allowing the user to go to the previous step. The “Continue” button dynamically changes to “Finish” on the last step. - Pagination: The current index is passed to the
Pagination
component, which updates the dot colors and indicator position.
Step 7: Integrating the Onboarding Component into a Screen
To use the Onboarding
component in your app, you can integrate it within a screen like this:
1export default function OnboardingScreen() {2 const [index, setIndex] = useState(0);3 const totalSteps = 3;45 return (6 <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>7 <Onboarding8 total={totalSteps}9 selectedIndex={index}10 onIndexChange={setIndex}11 />12 </View>13 );14}1516
Explanation:
- Managing State: We manage the current step using the
index
state. The total number of steps is set to 3, and we pass this to theOnboarding
component. - Handling Navigation: The
setIndex
function updates the current step, allowing the user to navigate through the onboarding steps.
Conclusion
By following these steps, you’ll be able to create a fully functional animated onboarding flow using React Native Reanimated. The components are modular and can be easily customized to fit your app's design. You can adjust the animations, layout, and overall behavior to provide a unique onboarding experience for your users.
Grab the codeloading...
Let me know if you need any more assistance!