react-native 用Animated实现卡片翻转效果

337 阅读1分钟

react-native实现类似贝壳找房的一个卡片翻转的效果。

实现效果就是如下图所示

Mar-14-2024 16-08-54.gif

实现的demo如下

import React, {Component, useState, useRef, useEffect} from 'react';
import {
  StyleSheet,
  SafeAreaView,
  Text,
  Image,
  View,
  Easing,
  TouchableOpacity,
  Animated,
} from 'react-native';
// 翻转卡片动画demo
const info = {
  cardType: 'front', // back
  text: '2室1厅/62.39m²',
  name: '12人关注此房',
  price: 415,
  url:
    'https://ke-image.ljcdn.com/110000-inspection/pc1_POwFMVR8O.jpg!m_fill,w_210,h_164,f_jpg?from=ke.com',
};
const Interpolate = () => {
  let timer = null;
  let rotateAnimatedRef = useRef(null);
  const [animatedValue, setAnimatedValue] = useState(new Animated.Value(0));
  const [cardInfo, setCardInfo] = useState(info);

  useEffect(() => {
    initAnimated();
    return () => {
      timer && clearTimeout(timer);
    };
  }, []);
  // 初始化的广告数据
  const initAnimated = () => {
    rotateAnimatedRef.current = Animated.timing(animatedValue, {
      useNativeDriver: true, // 启用原声动画
      toValue: 1,
      duration: 800,
      easing: Easing.in,
      perspective: 2000,
    });
    rotateAnimatedRef.current.start();
  };
  const _startAnimated = () => {
    timer = setTimeout(
      () => {
        if (cardInfo.cardType === 'front') {
          setCardInfo(info);
        } else {
          setCardInfo({
            color: 'red',
            text: '2室1厅/62.39m²',
            name: '12人关注此房',
            price: 415,
            url:
              'https://ke-image.ljcdn.com/110000-inspection/pc1_POwFMVR8O.jpg!m_fill,w_210,h_164,f_jpg?from=ke.com',
          });
        }
      }, //延时操作
      350, //延时时间
    );
    animatedValue.setValue(0);
    rotateAnimatedRef.current.start();
  };
  const rotateY = animatedValue.interpolate({
    inputRange: [0, 0.5, 1],
    outputRange: ['0deg', '90deg', '0deg'],
  });
  return (
    <SafeAreaView style={styles.mainStyle}>
      <Animated.View
        style={{
          alignSelf: 'center',
          width: 105,
          height: 180,
          // justifyContent: 'center',
          // alignItems: 'center',
          fontSize: 18,
          backgroundColor: '#ffffff',
          paddingBottom: 20,
          shadowColor: '#ccc',
          shadowOffset: {
            width: 1,
            height: -1,
          },
          shadowOpacity: 0.5,
          shadowRadius: 1,
          transform: [{rotateY: rotateY}],
        }}>
        <Image style={{width: 105, height: 80}} source={{uri: cardInfo.url}} />
        <View style={{marginTop: 8, paddingLeft: 4}}>
          <Text style={{fontSize: 12, color: '#000'}}>{cardInfo.text}</Text>
        </View>
        <View style={{marginTop: 8, paddingLeft: 4}}>
          <Text style={{fontSize: 12, color: '#000'}}>{cardInfo.name}</Text>
        </View>
        <View style={{marginTop: 8, paddingLeft: 4}}>
          <Text style={{fontSize: 12, color: 'red'}}>{cardInfo.price}万</Text>
        </View>
      </Animated.View>
      <TouchableOpacity style={styles.touchStyle} onPress={_startAnimated}>
        <Text
          style={{
            width: 200,
            height: 100,
            textAlign: 'center',
            lineHeight: 100,
          }}>
          点击开始动画
        </Text>
      </TouchableOpacity>
    </SafeAreaView>
  );
};
export default Interpolate;

const styles = StyleSheet.create({
  mainStyle: {
    flex: 1,
    backgroundColor: '#eee',
  },
  touchStyle: {
    padding: 10,
    alignSelf: 'flex-end',
  },
});

代码的实现效果

Mar-14-2024 16-14-12.gif