I am new to React Native Animation & I was following a tutorial & I did exactly what he was teaching but I failed to get the desired result. I am trying to develop a multipage onboarding screen with a svg animation. The problem is that it works fine but the moment I reach the last item in my flatlist, it doesn't update the index and hence the animation is not completed for the last array item.
Below is the relevant code:
RegisterationScreen:
const data = [
<EmailComponent />,
<PasswordComponent />,
<DPComponent />,
<AgeComponent />,
];
const RegisterScreen = () => {
const scrollX = useRef(new Animated.Value(0)).current;
const [currentIndex, setCurrentIndex] = useState(0);
const slidesRef = useRef(null);
const viewableItemsChanged = useCallback(({viewableItems}) => {
console.log(viewableItems[0]);
setCurrentIndex(viewableItems[0].index);
}, []);
const scrollTo = () => {
if (currentIndex < data.length - 1) {
slidesRef.current.scrollToIndex({index: currentIndex 1});
} else {
console.log('Last Item!');
}
};
const goBack = () => {
if (currentIndex === 0) {
return;
}
slidesRef.current.scrollToIndex({index: currentIndex - 1});
};
// console.log(currentIndex);
return (
<RegisterationStateProvider>
<View style={styles.container}>
<StatusBar barStyle="dark-content" backgroundColor="#ffffff" />
<SafeAreaView style={styles.back}>
<TouchableOpacity onPress={goBack} activeOpacity={0.6}>
<AntDesign name="arrowleft" size={32} color="black" />
</TouchableOpacity>
</SafeAreaView>
<View style={{flex: 3}}>
<FlatList
ref={slidesRef}
scrollEnabled
data={data}
keyExtractor={(_, index) => 'key' index}
renderItem={({item}) => item}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
bounces={false}
onScroll={
Animated.event(
[{nativeEvent: {contentOffset: {x: scrollX}}}],
{useNativeDriver: false},
)}
scrollEventThrottle={32}
onViewableItemsChanged={viewableItemsChanged}
/>
</View>
<Dot data={data} scrollX={scrollX} />
<NextButton
scrollTo={scrollTo}
percentage={(currentIndex 1) * (100 / data.length)}
/>
</View>
</RegisterationStateProvider>
);
};
NextButton:
const NextButton = ({percentage, scrollTo}) => {
const size = 100;
const strokeWidth = 4;
const center = size / 2;
const radius = size / 2 - strokeWidth / 2;
const circumference = 2 * Math.PI * radius;
// console.log(percentage);
const progressAnimation = useRef(new Animated.Value(0)).current;
const progressRef = useRef(null);
const animation = toValue => {
return Animated.timing(progressAnimation, {
toValue,
duration: 250,
useNativeDriver: false,
}).start();
};
useEffect(() => {
animation(percentage);
}, [percentage]);
useEffect(() => {
progressAnimation.addListener(
value => {
const strokeDashoffset =
circumference - (circumference * value.value) / 100;
if (progressRef?.current) {
progressRef.current.setNativeProps({
strokeDashoffset,
});
}
},
[percentage],
);
return () => {
progressAnimation.removeAllListeners();
};
}, []);
return (
<View style={styles.container}>
<Svg width={size} height={size}>
<G rotation="-90" origin={center}>
<Circle
stroke="#E6E7E8"
cx={center}
cy={center}
r={radius}
strokeWidth={strokeWidth}
/>
<Circle
ref={progressRef}
stroke="#FF5864"
cx={center}
cy={center}
r={radius}
strokeWidth={strokeWidth}
strokeDasharray={circumference}
strokeDashoffset={circumference}
/>
</G>
</Svg>
<TouchableOpacity
disabled={false}
onPress={scrollTo}
style={styles.button}
>
<AntDesign name="arrowright" size={35} color="#fff" />
</TouchableOpacity>
</View>
);
};
I cannot find the error/bug in the code, everything looks fine because when I check if (currentIndex < data.length - 1)
in scrollTo
function, it should render for index=3 because 3<4
is true obviously but unfortunately it doesn't work and no error in console either.
Below is the output of console for console.log(currentIndex);
& console.log(percentage);
LOG {"index": 0, "isViewable": true, "item": <EmailComponent />, "key": "key0"}
LOG {"index": 0, "isViewable": true, "item": <EmailComponent />, "key": "key0"}
LOG {"index": 1, "isViewable": true, "item": <PasswordComponent />, "key": "key1"}
LOG {"index": 1, "isViewable": true, "item": <PasswordComponent />, "key": "key1"}
LOG {"index": 2, "isViewable": true, "item": <DPComponent />, "key": "key2"}
LOG 0
LOG 25
LOG 1
LOG 50
LOG 2
LOG 75
As you can see that even though I am at the last item, the animation is still at (75%) 270° & not full complete i.e. (100%) 360° & {index:3} is not logging in console even though I'm at last item of data.
CodePudding user response:
onViewableItemsChanged
is not being triggered on the last item in the FlatList. Lower the viewAreaCoveragePercentThreshold
in the viewabilityConfig
property https://reactnative.dev/docs/flatlist#viewabilityconfig