here is the below code MAIN CODE :
import React, { useEffect, useRef, useState } from 'react';
import { View, Text, SafeAreaView, StyleSheet, Image, FlatList, TouchableOpacity, StatusBar, Alert } from 'react-native';
import { colorsTemp } from '../configuration/Colors';
import { colors } from '../constants/Colors';
import { width } from '../constants/Scales';
import { useNavigation } from '@react-navigation/native';
import { slides } from '../data/onboarddata';
import Icon from 'react-native-vector-icons/FontAwesome';
import Animated, { useAnimatedStyle, withSpring } from 'react-native-reanimated';
import OnboardBtn from '../components/common/OnboardBtn';
import { centerViewStyle } from '../constants/Styles';
import Loader from '../components/Loaders/Loader.js';
const Onboarding = () => {
const navigation = useNavigation();
const [isLoading, setIsLoading] = useState(false);
const [currIndex, setCurrIndex] = useState(0);
const ref = useRef(null);
const ref2 = useRef(null);
const [onboardSlides, setOnboardSlides] = useState(null);
useEffect(() => {
setOnboardSlides(slides);
}, []);
const handleIndexChange = () => {
if (currIndex < (onboardSlides.length - 1)) {
setCurrIndex(currIndex + 1);
const currentIndex = currIndex + 1;
const offset = currentIndex * width;
ref?.current.scrollToOffset({ offset });
ref2?.current.scrollToOffset({ offset });
}
};
const updateCurrentIndex = (e) => {
const contentOffsetX = e.nativeEvent.contentOffset.x;
const currIndex = Math.round(contentOffsetX / width);
setCurrIndex(currIndex);
const offset = currIndex * width;
ref?.current.scrollToOffset({ offset });
ref2?.current.scrollToOffset({ offset });
};
const renderText = ({ item }) => (
<View style={style.textContainer}>
<View style={{ width: width * 0.75, textAlign: 'center' }}>
<Text style={style.title}>{item.title}</Text>
<Text style={style.description}>{item.subtitle}</Text>
</View>
</View>
);
const renderItem = ({ item }) => (
<View style={style.onboardImageContainer}>
<Image source={item.image} style={style.onboardImage} resizeMode='stretch' />
</View>
);
const renderIndicators = () => {
if (!slides || slides.length === 0) return null;
const indicators = slides.map((slide, index) => {
const indicatorStyle = animatedStyle(currIndex === index);
return <Animated.View key={index} style={[style.indicator, indicatorStyle]} />;
});
return (
<View style={style.scrollIndicator}>
{indicators}
</View>
);
};
const animatedStyle = (isActive) => useAnimatedStyle(() => {
const widthVal = withSpring(isActive ? 45 : 12, {
mass: 1,
damping: 4,
stiffness: 100,
overshootClamping: false,
});
const backgroundColor = withSpring(isActive ? colors.primary : colors.tertiary);
return {
width: widthVal,
backgroundColor,
};
});
return (
<SafeAreaView style={style.safeArea}>
<StatusBar backgroundColor='black' barStyle='dark-content' />
{isLoading ? (
<Loader />
) : onboardSlides && onboardSlides.length > 0 ? (
<>
<View style={style.onboardImageWrapper}>
<FlatList
data={onboardSlides}
renderItem={renderItem}
keyExtractor={(item) => item.id}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
onMomentumScrollEnd={updateCurrentIndex}
ref={ref}
/>
</View>
<View style={style.textParentContainer}>
<FlatList
data={onboardSlides}
renderItem={renderText}
keyExtractor={(item) => item.id}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
onMomentumScrollEnd={updateCurrentIndex}
ref={ref2}
/>
{renderIndicators()}
</View>
<View style={[style.footer, (currIndex === (onboardSlides.length - 1)) && { justifyContent: 'center' }]}>
{currIndex === (onboardSlides.length - 1) ? (
<View style={style.onboardBtnWrapper}>
<OnboardBtn
handlePress={() => null}
label="Already Registered? Log in"
buttonStyle={style.btnStyle}
btnTextStyle={style.alreadyRegisteredBtn}
/>
<OnboardBtn
handlePress={() => null}
label="Let's Get Started"
buttonStyle={style.btnStyle}
btnTextStyle={style.getStartBtn}
/>
</View>
) : (
<TouchableOpacity onPress={() => handleIndexChange()} style={style.skipBtn}>
<Icon name="long-arrow-right" size={30} color={colors.onSecondary} />
</TouchableOpacity>
)}
</View>
</>
) : null}
</SafeAreaView>
);
};
const commonBtn = {
textAlign: 'center',
textAlignVertical: 'center',
flex: 1,
borderRadius: 10,
fontWeight: 'bold',
fontSize: 18,
fontFamily: 'Anta-Regular',
};
const style = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: colorsTemp.background,
},
onboardImageWrapper: {
flex: 0.6,
...centerViewStyle,
},
onboardImageContainer: {
flex: 1,
...centerViewStyle,
},
carousalImage: {
width: width,
height: '100%',
},
textParentContainer: {
flex: 0.25,
...centerViewStyle,
width: width,
},
textContainer: {
width: width,
flex: 1,
...centerViewStyle,
},
title: {
fontFamily: 'RobotoSlab-VariableFont_wght',
fontSize: 30,
color: colors.secondary,
fontWeight: 'bold',
textAlign: 'center',
},
description: {
fontSize: 20,
marginTop: 20,
...centerViewStyle,
textAlign: 'center',
color: colors.tertiary,
fontFamily: 'Anta-Regular',
},
scrollIndicator: {
width: width * 0.15,
marginTop: 10,
marginBottom: 10,
flexDirection: 'row',
alignItems: 'center',
},
indicator: {
// width: 27,
borderRadius: 5,
height: 8,
color: colors.onSecondary,
marginEnd: 4,
},
activeIndicator: {
// width: 45,
backgroundColor: colors.primary,
},
footer: {
flex: 0.15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end',
paddingHorizontal: 8,
},
skipBtn: {
fontWeight: 'bold',
fontSize: 16,
marginEnd: 10,
color: colors.secondary,
},
btnStyle: {
flex: 0.39,
width: '100%',
},
getStartBtn: {
backgroundColor: colors.primary,
color: colors.onSecondary,
...commonBtn,
},
alreadyRegisteredBtn: {
backgroundColor: colors.tertiary,
color: colors.onSecondary,
...commonBtn,
},
onboardBtnWrapper: {
flex: 1,
...centerViewStyle,
paddingHorizontal: 8,
gap: 10,
},
onboardImage: {
flex: 0.9,
width: width,
borderRadius: 20,
},
skipBtn: {
backgroundColor: colors.tertiary,
borderRadius: 100,
padding: 10,
},
});
export default Onboarding;
if you need the dummy slides data here it is
const slides = [
{
id: 1,
title: "Find Best Salon's Nearby",
image: require("../assets/images/barbershop_rmbg.gif"),
subtitle: 'Choose Your Type Salon from different options available Find Your Gromming Partner Today'
},
{
id: 2,
title: "Attractive Promotions & Offers",
image: require("../assets/images/promotion_rmbg.gif"),
subtitle: 'Get Attrative Offers and Discounts (%) on Your Favourite Salon'
},
{
id: 3,
title: "Professional Salon Specialists",
image: require("../assets/images/specialist_rmbg.gif"),
subtitle: 'Choose Your Best Stylist from Our Top Professional Specialists'
}
]
export {slides}
Note everything is setup properly i have tested and used it but i dont know why the animation is not displaying properly the indicators are working properly but the animation is not shown on them. please help me
dont dislike as i already loosed my account made a new account i dont know why they are doing to me only even my questions were genuine
If you look in the code the animation is working correctly when i have not use the onboardSlides useState and useEffect like this
<View style={style.textParentContainer}>
<FlatList
data={onboardSlides}
renderItem={renderText}
keyExtractor={(item) => item.id}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
onMomentumScrollEnd={updateCurrentIndex}
ref={ref2}
/>
<View style={style.scrollIndicator}>
{onboardSlides.map((item, index) => (
<Animated.View key={index} style={[style.indicator, animatedStyle(currIndex === index)]} />
))
}
</View>
but why it is not working properly with useEffect and useState **here might be the useAnimatedStyle is in condition that is whyy it is giving error as rendered more than previous render ** i dont know how to solve the problem not