React Native Map功能中的随机动画- Expo -Reanimated 2

jv2fixgn  于 2022-12-14  发布在  React
关注(0)|答案(1)|浏览(191)

我有一个有四个动画视图的屏幕。它们是由一个Map函数渲染的。当屏幕被安装时,一个缩放动画被触发一次。之后,我试图实现随机动画(缩放简单动画)每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',
  }
})
o8x7eapl

o8x7eapl1#

你想每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",
  },
});

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

相关问题