使用 Animated React Native Expo 缩放图像不会永久应用

Scale an image with Animated react native expo is not applying permanently

我正在尝试在用户按下时增加图像的大小,并在用户再次按下时使用以下动画 API 缩小图像:

const [viewState, setViewState]= useState(true);
const scaleAnim = (new Animated.Value(.9))




const scaleOut = () => {

if(viewState){
  Animated.timing(scaleAnim, {
    toValue: 2.2,
    duration: 2000,
    useNativeDriver:true,
  }).start(()=>{setViewState(false)});
}
else{
  Animated.timing(scaleAnim, {
    toValue: .9,
    duration: 700,
    useNativeDriver:true,
  }).start(setViewState(true));
}

 };

    <Animated.View style={{transform:[{scale:scaleAnim}]}} >
      <Image style={styles.image} source={require('../path..')} />
    </Animated.View>


const styles = StyleSheet.create({
  image: {
    width:70,
    resizeMode:"contain",
    height: 45,
    alignSelf: "center",
  },

但问题是,只要持续时间结束,尺寸就会恢复到默认值。我想永久保留并在用户再次按下时做相反的事情(减小尺寸)

有什么建议吗?

创建了一个组件希望这是你想要的....

小吃:https://snack.expo.io/neEtc2ihJ


export default function App() {
  const [viewState, setViewState] = React.useState(true);
  const scale = React.useRef(new Animated.Value(1)).current;
  const [init, setInit] = React.useState(true);
  React.useEffect(() => {
    if (init) {
      setInit(false);
    } else {
      if (viewState) {
        Animated.timing(scale, {
          toValue: 2,
          duration: 1000,
          useNativeDriver: true,
        }).start();
      } else {
        Animated.timing(scale, {
          toValue: 0.5,
          duration: 700,
          useNativeDriver: true,
        }).start();
      }
    }
  }, [viewState]);

  const scaleOut = () => {
    setViewState(!viewState);
  };

  return (
    <View style={styles.container}>
      <Animated.View style={{ transform: [{ scale }] }}>
        <Image
          style={styles.image}
          source={require('./assets/snack-icon.png')}
        />
      </Animated.View>
      <Button title="animate" onPress={scaleOut} />
    </View>
  );
}

首先,您希望动画值为 useStateuseRef。 react-native 示例使用 useRef,所以我建议您也这样做。我还建议您使用插值来缩放,以便您可以将更多动画与该动画值相关联。结果将是这样的:

    const animatedValue = useRef(new Animated.Value(0)).current;   
    const [ toggle, setToggle ] = useState(false)
    const scaleOut = () => {
      let animation
      if(!toggle){
        animation = Animated.timing(animatedValue, {
          toValue: 1,
          duration: 700,
          useNativeDriver:true,
        });
      }
      else{
        animation = Animated.timing(animatedValue, {
          toValue: 0,
          duration: 2000,
          useNativeDriver:true,
        });
      }
      animation.start(()=>{
        setToggle(!toggle)
      })
    };
    let scaleAnim = animatedValue.interpolate({
      inputRange:[0,1],
      outputRange:[0.9,2.2]
    })
    return (
      <Animated.View style={{transform:[{scale:scaleAnim}]}} >
        <TouchableOpacity onPress={scaleOut}>
          <Image style={styles.image} source={require('../path..')} />
        </TouchableOpacity>
      </Animated.View>
    );

通过这样做,您可以通过添加另一个插值来将多张图像缩放为您想要的任何大小。但是,如果您不想这样做:

    const scaleOut = () => {
      let animation
      if(!toggle){
        animation = Animated.timing(animatedValue, {
          toValue: 2.2,
          duration: 2000,
          useNativeDriver:true,
        });
      }
      else{
        animation = Animated.timing(animatedValue, {
          toValue: 0.9,
          duration: 700,
          useNativeDriver:true,
        });
      }
      animation.start(()=>{
        setToggle(!toggle)
      })
    };
    return (
      <Animated.View style={{transform:[{scale:animatedValue}]}} >
        <TouchableOpacity onPress={scaleOut} />
          <Image style={styles.image} source={require('../path..')} />
        </TouchableOpacity>
      </Animated.View>
    );

如果您想更进一步,将 TouchableOpacity 换成 Pressable,将动画放在 Animated.loop 中并在 onPressIn 中启动,在 pressOut 时停止动画并设置 animatedValue回到初始值:

    const onPressIn= ()=>{
      Animated.loop([
        Animated.timing(animatedValue, {
          toValue: 2.2,
          duration: 2000,
          useNativeDriver:true,
        }),
        Animated.timing(animatedValue, {
          toValue: 0.9,
          duration: 700,
          useNativeDriver:true,
        });
      ],{useNativeDriver:true}).start()
    }
    const onPressOut= ()=>{
      animatedValue.stop()
      Animated.timing(animatedValue,{
          toValue: 0.9,
          duration: 700,
          useNativeDriver:true,
      })
    }
    return(
      <Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
        <Animated.View style={{transform:[{scale:animatedValue}]}} >
            <Image style={styles.image} source={require('../path..')} />
        </Animated.View>
      </Pressable>
    );