reactjs React-native在数字和字符串值之间动画

pwuypxnk  于 5个月前  发布在  React
关注(0)|答案(1)|浏览(56)

我正在尝试更新一个旧代码。我分享的代码中出现了一些问题,我无法找出原因,因为我不完全精通复活库。如果有人能帮助我,我将不胜感激。我正在创建一个投票屏幕,根据屏幕上触摸的星星,我将改变我分享的照片中可见的面部表情。
RatingScreen.js

import React from 'react';
import { TouchableOpacity, StyleSheet, Text, View, Dimensions } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import Animated, { Easing, useSharedValue, withSpring, useAnimatedStyle } from 'react-native-reanimated';
import * as flubber from 'flubber';
import Svg, { G, Path } from 'react-native-svg';
import Icon1 from 'react-native-vector-icons/Feather';

const { width, height } = Dimensions.get('screen');

const fill = "#333";
const types = ['upset', 'sad', 'neutral', 'smile', 'excited'];
const PATHS = {
  "upset": "M141.5 132.55C140.92 75.87 120.92 48.22 81.5 49.63C42.09 51.03 22.09 78.67 21.5 132.55L141.5 132.55Z",
  "sad": "M122.32 87.65C121.94 68.08 108.83 58.53 83 59.02C57.17 59.5 44.06 69.04 43.68 87.65L122.32 87.65Z",
  "neutral": "M38.02 58.05L99.77 40.83L102.99 52.35L41.23 69.57L38.02 58.05Z",
  "smile": "M122.32 64.68C121.94 84.25 108.83 93.79 83 93.31C57.17 92.82 44.06 83.28 43.68 64.68L122.32 64.68Z",
  "excited": "M142.99 49.74C142.4 106.42 122.4 134.06 82.99 132.66C43.57 131.26 23.57 103.62 22.99 49.74L142.99 49.74Z",
  "left-eye": "M30.43 16.78C30.43 24.39 24.29 30.57 16.72 30.57C9.15 30.57 3 24.39 3 16.78C3 9.18 9.15 3 16.72 3C24.29 3 30.43 9.18 30.43 16.78Z",
  "right-eye": "M162.99 16.79C162.99 24.4 156.84 30.57 149.27 30.57C141.7 30.57 135.56 24.4 135.56 16.79C135.56 9.18 141.7 3.01 149.27 3.01C156.84 3.01 162.99 9.18 162.99 16.79Z"
};

const GRADIENTS = {
  "upset": ["rgb(231, 97, 97)", "rgb(236, 49, 49)"],
  "sad": ["rgb(247,152,48)", "rgb(231, 97, 97)"],
  "neutral": ["rgb(243, 189, 67)", "rgb(203,96,32)"],
  "smile": ["rgb(238,172,77)", "rgb(187, 230, 95)"],
  "excited": ["rgb(95,230,118)", "rgb(46, 232, 78)"],
};

class RatingScreen extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      path: PATHS.neutral,
      background: GRADIENTS.neutral,
      type: "neutral",
      index: -1,
      progress: new Animated.Value(0),
    };
  }

  interpolatePaths = (type, index) => {
    const interpolator = flubber.interpolate(this.state.path, PATHS[type], { maxSegmentLength: 2 });
    Animated.timing(this.state.progress, {
      toValue: 1,
      duration: 400,
      easing: Easing.inOut(Easing.ease),
      useNativeDriver: false,
    }).start(() => {
      this.setState({
        path: interpolator(1),
        background: GRADIENTS[type],
        type,
        index,
      });
      this.state.progress.setValue(0);
    });
  };

  render() {
    const animatedStyle = {
      d: this.state.path,
      background: this.state.background,
    };

    return (
      <LinearGradient colors={this.state.background} style={styles.gradient}>
        <View style={styles.headings}>
          <Text style={styles.heading}>Please rate your feedback</Text>
        </View>
        <View style={styles.svgWrapper}>
          <Svg width={width} height={height / 3} viewBox="0 0 166 136" style={styles.svgContainer}>
            <G>
              <Path d={PATHS["left-eye"]} fill={fill} />
              <Animated.View style={animatedStyle}>
                <Path d={PATHS["right-eye"]} fill={fill} />
              </Animated.View>
            </G>
          </Svg>
          <View style={styles.feedbackWrapper}>
            {types.map((type, index) => (
              <TouchableOpacity key={type} onPress={() => this.interpolatePaths(type, index)}>
                <Icon1 name={this.state.index >= index ? "star" : "star"} size={32} color="#fff" />
              </TouchableOpacity>
            ))}
          </View>
        </View>
      </LinearGradient>
    );
  }
}

const styles = StyleSheet.create({
  gradient: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  feedbackWrapper: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-around',
    height: 60,
    borderRadius: 30,
    backgroundColor: "rgba(0, 0, 0, 0.05)",
    width: width * .9
  },
  headings: {
    flex: .3,
    justifyContent: "center"
  },
  heading: {
    color: "#fff",
    fontSize: 42,
    lineHeight: 42,
    fontWeight: '700'
  },
  body: {
    color: "#fff",
    fontFamily: "Menlo"
  },
  svgContainer: {
    marginBottom: 40
  },
  svgWrapper: {
    flex: .6,
    alignItems: "center",
    justifyContent: "center"
  }
});

export default RatingScreen;

字符串


的数据



旧代码

import React from 'react';
import { TouchableOpacity, StyleSheet, Text, View, Dimensions } from 'react-native';
import Gradient from 'react-native-css-gradient';
import { interpolate } from 'flubber';
import { tween, easing } from 'popmotion';
import { Svg } from 'expo'
import { AntDesign } from '@expo/vector-icons';

const { width, height } = Dimensions.get('screen');
const { Path, G } = Svg;

const fill = "#333";
const types = ['upset', 'sad', 'neutral', 'smile', 'excited'];
const PATHS = {
  "upset": "M141.5 132.55C140.92 75.87 120.92 48.22 81.5 49.63C42.09 51.03 22.09 78.67 21.5 132.55L141.5 132.55Z",
  "sad": "M122.32 87.65C121.94 68.08 108.83 58.53 83 59.02C57.17 59.5 44.06 69.04 43.68 87.65L122.32 87.65Z",
  "neutral": "M38.02 58.05L99.77 40.83L102.99 52.35L41.23 69.57L38.02 58.05Z",
  "smile": "M122.32 64.68C121.94 84.25 108.83 93.79 83 93.31C57.17 92.82 44.06 83.28 43.68 64.68L122.32 64.68Z",
  "excited": "M142.99 49.74C142.4 106.42 122.4 134.06 82.99 132.66C43.57 131.26 23.57 103.62 22.99 49.74L142.99 49.74Z",
  "left-eye": "M30.43 16.78C30.43 24.39 24.29 30.57 16.72 30.57C9.15 30.57 3 24.39 3 16.78C3 9.18 9.15 3 16.72 3C24.29 3 30.43 9.18 30.43 16.78Z",
  "right-eye": "M162.99 16.79C162.99 24.4 156.84 30.57 149.27 30.57C141.7 30.57 135.56 24.4 135.56 16.79C135.56 9.18 141.7 3.01 149.27 3.01C156.84 3.01 162.99 9.18 162.99 16.79Z"
};
const GRADIENTS = {
  "upset": "linear-gradient(to bottom, rgb(231, 97, 97), rgb(236, 49, 49))",
  "sad": "linear-gradient(to bottom, rgb(247,152,48), rgb(231, 97, 97))",
  "neutral": "linear-gradient(to bottom, rgb(243, 189, 67), rgb(203,96,32))",
  "smile": "linear-gradient(to bottom, rgb(238,172,77), rgb(187, 230, 95))",
  "excited": "linear-gradient(to bottom, rgb(95,230,118), rgb(46, 232, 78))",
};

export default class App extends React.Component {
  state = {
    path: PATHS.neutral,
    background: GRADIENTS.neutral,
    type: "neutral",
    index: -1
  }

  interpolatePaths = (type, index) => {
    const interpolator = interpolate(this.state.path, PATHS[type], { maxSegmentLength: 2 });
    tween({
      duration: 400,
      ease: easing.easeInOut,
      from: { i: 0, background: this.state.background },
      to: { i: 1, background: GRADIENTS[type] }
    })
      .pipe(({ i, background }) => ({ path: interpolator(i), background }))
      .start(({ path, background }) => {
        this.setState({
          path, background, type, index
        })
      })
  }

  render() {
    return (
      <Gradient gradient={this.state.background} style={styles.gradient}>
        <View style={styles.headings}>
          <Text style={styles.heading}>Please rate your feedback</Text>
          <Text style={styles.body}>Do let us know your thoughts.</Text>
          <Text style={styles.body}>Your feedback matters!</Text>
        </View>
        <View style={styles.svgWrapper}>
          <Svg width={width} height={height / 3} viewBox="0 0 166 136" style={styles.svgContainer}>
            <G>
              <Path d={PATHS["left-eye"]} fill={fill} />
              <Path d={this.state.path} fill={fill} />
              <Path d={PATHS["right-eye"]} fill={fill} />
            </G>
          </Svg>
          <View style={styles.feedbackWrapper}>
            {types.map((type, index) => (
              <TouchableOpacity key={type} onPress={() => this.interpolatePaths(type, index)}>
                <AntDesign name={this.state.index >= index ? "star" : "staro"} size={32} color="#fff" />
              </TouchableOpacity>
            ))}
          </View>
        </View>
      </Gradient>
    );
  }
}

const styles = StyleSheet.create({
  gradient: {
    width,
    height,
    alignItems: "center",
  },
  feedbackWrapper: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-around',
    height: 60,
    borderRadius: 30,
    backgroundColor: "rgba(0, 0, 0, 0.05)",
    width: width * .9
  },
  headings: {
    flex: .4,
    justifyContent: "center"
  },
  heading: {
    color: "#fff",
    fontSize: 42,
    lineHeight: 42,
    fontWeight: '700'
  },
  body: {
    color: "#fff",
    fontFamily: "Menlo"
  },
  svgContainer: {
    marginBottom: 40
  },
  svgWrapper: {
    flex: .6,
    alignItems: "center",
    justifyContent: "center"
  }
});


我试过旧图书馆,但它不工作
我试过这样做,但它没有工作,我不知道如何使用popmotion

import React from 'react';
import { TouchableOpacity, StyleSheet, Text, View, Dimensions } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import * as flubber from 'flubber';
import { animate, easeInOut } from 'popmotion';
import Svg, { G, Path } from 'react-native-svg';
import Icon1 from 'react-native-vector-icons/Feather';

const { width, height } = Dimensions.get('screen');

const fill = "#333";
const types = ['upset', 'sad', 'neutral', 'smile', 'excited'];
const PATHS = {
  "upset": "M141.5 132.55C140.92 75.87 120.92 48.22 81.5 49.63C42.09 51.03 22.09 78.67 21.5 132.55L141.5 132.55Z",
  "sad": "M122.32 87.65C121.94 68.08 108.83 58.53 83 59.02C57.17 59.5 44.06 69.04 43.68 87.65L122.32 87.65Z",
  "neutral": "M38.02 58.05L99.77 40.83L102.99 52.35L41.23 69.57L38.02 58.05Z",
  "smile": "M122.32 64.68C121.94 84.25 108.83 93.79 83 93.31C57.17 92.82 44.06 83.28 43.68 64.68L122.32 64.68Z",
  "excited": "M142.99 49.74C142.4 106.42 122.4 134.06 82.99 132.66C43.57 131.26 23.57 103.62 22.99 49.74L142.99 49.74Z",
  "left-eye": "M30.43 16.78C30.43 24.39 24.29 30.57 16.72 30.57C9.15 30.57 3 24.39 3 16.78C3 9.18 9.15 3 16.72 3C24.29 3 30.43 9.18 30.43 16.78Z",
  "right-eye": "M162.99 16.79C162.99 24.4 156.84 30.57 149.27 30.57C141.7 30.57 135.56 24.4 135.56 16.79C135.56 9.18 141.7 3.01 149.27 3.01C156.84 3.01 162.99 9.18 162.99 16.79Z"
};

const GRADIENTS = {
  "upset": ["rgb(231, 97, 97)", "rgb(236, 49, 49)"],
  "sad": ["rgb(247,152,48)", "rgb(231, 97, 97)"],
  "neutral": ["rgb(243, 189, 67)", "rgb(203,96,32)"],
  "smile": ["rgb(238,172,77)", "rgb(187, 230, 95)"],
  "excited": ["rgb(95,230,118)", "rgb(46, 232, 78)"],
};


export default class RatingScreen extends React.Component {
  state = {
    path: PATHS.neutral,
    background: GRADIENTS.neutral,
    type: "neutral",
    index: -1
  }

  interpolatePaths = (type, index) => {
    const interpolator = flubber.interpolate(this.state.path, PATHS[type], { maxSegmentLength: 2 });
    animate({
      duration: 400,
      ease: easeInOut,
      from: { i: 0, background: this.state.background },
      to: { i: 1, background: GRADIENTS[type] }
    })
      .pipe(({ i, background }) => ({ path: interpolator(i), background }))
      .start(({ path, background }) => {
        this.setState({
          path, background, type, index
        })
      })
  }

  render() {
    return (
      <LinearGradient colors={this.state.background} style={styles.gradient}>
        <View style={styles.headings}>
          <Text style={styles.heading}>Please rate your feedback</Text>
        </View>
        <View style={styles.svgWrapper}>
          <Svg width={width} height={height / 3} viewBox="0 0 166 136" style={styles.svgContainer}>
            <G>
              <Path d={PATHS["left-eye"]} fill={fill} />
              <Path d={this.state.path} fill={fill} />
              <Path d={PATHS["right-eye"]} fill={fill} />
            </G>
          </Svg>
          <View style={styles.feedbackWrapper}>
            {types.map((type, index) => (
              <TouchableOpacity key={type} onPress={() => this.interpolatePaths(type, index)}>
                <Icon1 name={this.state.index >= index ? "star" : "star"} size={32} color="#fff" />
              </TouchableOpacity>
            ))}
          </View>
        </View>
      </LinearGradient>
    );
  }
}

const styles = StyleSheet.create({
  gradient: {
    width,
    height,
    alignItems: "center",
  },
  feedbackWrapper: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-around',
    height: 60,
    borderRadius: 30,
    backgroundColor: "rgba(0, 0, 0, 0.05)",
    width: width * .9
  },
  headings: {
    flex: .3,
    justifyContent: "center"
  },
  heading: {
    color: "#fff",
    fontSize: 42,
    lineHeight: 42,
    fontWeight: '700'
  },
  body: {
    color: "#fff",
    fontFamily: "Menlo"
  },
  svgContainer: {
    marginBottom: 40
  },
  svgWrapper: {
    flex: .6,
    alignItems: "center",
    justifyContent: "center"
  }
});

kx1ctssn

kx1ctssn1#

由于我使用的库的问题,我切换到不同的库,放弃了用线性改变背景颜色。通过使用一些简单的Reanimated函数,我用一个简单的代码取得了成功。

import React from 'react';
import { TouchableOpacity, StyleSheet, View, Dimensions, Text, TouchableWithoutFeedback } from 'react-native';
import Svg, { G, Path } from 'react-native-svg';
import Icon from 'react-native-vector-icons/AntDesign';
import Animated, { useSharedValue, useAnimatedProps, withTiming, Easing } from 'react-native-reanimated';
import { parse, interpolatePath } from 'react-native-redash';
import LinearGradient from 'react-native-linear-gradient';

const { width, height } = Dimensions.get('screen');
const fill = "white";
const lefteye = "M30.43 16.78C30.43 24.39 24.29 30.57 16.72 30.57C9.15 30.57 3 24.39 3 16.78C3 9.18 9.15 3 16.72 3C24.29 3 30.43 9.18 30.43 16.78Z";
const righteye = "M162.99 16.79C162.99 24.4 156.84 30.57 149.27 30.57C141.7 30.57 135.56 24.4 135.56 16.79C135.56 9.18 141.7 3.01 149.27 3.01C156.84 3.01 162.99 9.18 162.99 16.79Z";

const App = ({ }) => {
  const AnimatedPath = Animated.createAnimatedComponent(Path);
  const progress = useSharedValue(0);
  const [rating, setRating] = React.useState(0);

  const expressions = [
    parse("M141.5 132.55C140.92 75.87 120.92 48.22 81.5 49.63C42.09 51.03 22.09 78.67 21.5 132.55L141.5 132.55Z"),
    parse("M122.32 87.65C121.94 68.08 108.83 58.53 83 59.02C57.17 59.5 44.06 69.04 43.68 87.65L122.32 87.65Z"),
    parse("M38.02 58.05L99.77 40.83L102.99 52.35L41.23 69.57L38.02 58.05Z"),
    parse("M122.32 64.68C121.94 84.25 108.83 93.79 83 93.31C57.17 92.82 44.06 83.28 43.68 64.68L122.32 64.68Z"),
    parse("M142.99 49.74C142.4 106.42 122.4 134.06 82.99 132.66C43.57 131.26 23.57 103.62 22.99 49.74L142.99 49.74Z"),
  ];

  const animatedProps = useAnimatedProps(() => {
    return {
      d: interpolatePath(progress.value, [0, 1, 2, 3, 4], expressions),
    };
  });

  const handleStarPress = (value) => {
    setRating(value);
    progress.value = withTiming(value, { duration: 530, easing: Easing.bezier(0.33, 1, 0.68, 1) });
  };

  const renderStar = (value) => (
    <TouchableOpacity onPress={() => handleStarPress(value)}>
      <Icon name={rating >= value ? "star" : "staro"} size={32} color={fill} />
    </TouchableOpacity>
  );

  return (
    <LinearGradient style={styles.container} colors={['#1d4c1e', '#151618']}>
      <View style={styles.svgWrapper}>
        <View style={{ width: width, alignItems: 'center' }}>
          <Svg width={width} height={height / 4} viewBox="0 0 166 136" style={styles.svgContainer}>
            <G>
              <Path d={lefteye} fill={fill} />
              <AnimatedPath animatedProps={animatedProps} fill={fill} />
              <Path d={righteye} fill={fill} />
            </G>
          </Svg>
        </View>
      </View>

      <View style={styles.feedbackWrapper}>
        {renderStar(0)}
        {renderStar(1)}
        {renderStar(2)}
        {renderStar(3)}
        {renderStar(4)}
      </View>
    </LinearGradient>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: 'center',
    paddingBottom: 40,
    backgroundColor: 'white'
  },
  feedbackWrapper: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-around',
    width: width * .9,
    position: 'absolute',
    bottom: 50,
  },
  headings: {
    justifyContent: "center"
  },
  heading: {
    color: "white",
    lineHeight: 20,
    fontFamily: "Poppins-SemiBold",
    fontSize: 16,
  },
  svgContainer: {
    marginBottom: 40
  },
  svgWrapper: {
    alignItems: "center",
    justifyContent: "center"
  },
});

export default App;

字符串

相关问题