地图功能中的随机动画- Expo - Reanimated2



我有一个带有四个动画视图的屏幕。它们由映射函数呈现。当屏幕被安装时,缩放动画被触发一次。在那之后,我试图实现随机动画(缩放简单动画)每4秒只有一个视图。我找不到方法来获得每个视图的参考,只随机地动画一个。下面是我的代码:

import { useRef, useEffect } from 'react'
import { View, StyleSheet, TouchableOpacity } from 'react-native'
import Animated, { useAnimatedStyle, useSharedValue, withTiming, withSpring, withRepeat } from 'react-native-reanimated'
const SIZE = 65.0
const RandomZoomInScreen = ({ navigation }) => {
const scale = useSharedValue(0)
const bounce = useSharedValue(1)
const itemEls = useRef(new Array())
const reanimatedStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }]
}
})
const bounceStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: bounce.value }]
}
})
useEffect(() => {
scale.value = withSpring(1, {stiffness:200})
return () => {
scale.value = 0
}
}, [])
useEffect(() => {
const intervalId = setInterval(() => {  //assign interval to a variable to clear it.
'worklet'
bounce.value = withRepeat(withTiming(1.3),2,true)
}, 4000)

return () => clearInterval(intervalId)
}, [])
return (
<View style={styles.container}>
{[1, 2, 3, 4].map((square, index) => {
return <TouchableOpacity
activeOpacity={0.7}
key={index}
>
<Animated.View 

ref={(element) => itemEls.current.push(element)} style={[styles.square, reanimatedStyle, bounceStyle]} />
</TouchableOpacity>
})}
</View>
)
}
export default RandomZoomInScreen
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-evenly',
alignItems: 'center'
},
square: {
width: SIZE * 2,
height: SIZE,
backgroundColor: 'green',
}
})

你想每4秒动画一个盒子,对吗?

如果你想让单个盒子动起来,我认为最好的方法是为每个盒子创建单独的共享值,通过创建一个box组件,或者创建一个共享值数组(或类似的东西),这样你就可以独立地改变每个值。

我在这里重构了你的代码,创建了一个Box组件,并在组件内部创建了一个scale共享值:

import { useEffect, useState } from "react";
import { View, StyleSheet, TouchableOpacity } from "react-native";
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
withSequence,
withTiming,
} from "react-native-reanimated";
const SIZE = 65.0;
const Box = ({ shouldAnimate }) => {
const scale = useSharedValue(0);
const reanimatedStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
};
});
useEffect(() => {
scale.value = withSpring(1, { stiffness: 200 });
return () => {
scale.value = 0;
};
}, []);
useEffect(() => {
if (shouldAnimate) {
scale.value = withSequence(withTiming(1.3), withTiming(1));
}
}, [shouldAnimate]);
return (
<TouchableOpacity activeOpacity={0.7}>
<Animated.View style={[styles.square, reanimatedStyle]} />
</TouchableOpacity>
);
};
const RandomZoomInScreen = ({ navigation }) => {
const [selectedBox, setSelectedBox] = useState(-1);
useEffect(() => {
const intervalId = setInterval(() => {
// you want to select a number between 0 and 3 (the indeces of the boxes) every 4 seconds
const nextBox = Math.floor(Math.random() * 4);
// to garantee the new value will always be different from previous one...
// we can sum 1 and apply a mod 4 (so the result is always between 0 and 3)
setSelectedBox((previousBox) =>
previousBox === nextBox ? (nextBox + 1) % 4 : nextBox
);
}, 4000);
return () => clearInterval(intervalId);
}, []);
return (
<View style={styles.container}>
{[1, 2, 3, 4].map((square, index) => {
// we should animate when the selected box is equal to the index
return <Box key={square} shouldAnimate={index === selectedBox} />;
})}
</View>
);
};
export default RandomZoomInScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "space-evenly",
alignItems: "center",
},
square: {
width: SIZE * 2,
height: SIZE,
backgroundColor: "green",
},
});

请记住,可能还有其他方法可以实现这一点。

相关内容

最新更新