【问题标题】:Circling motion animation in React NativeReact Native 中的圆周运动动画
【发布时间】:2020-02-04 02:34:05
【问题描述】:

我需要创建一个动画,其中一个图像将围绕另一个图像旋转。我已经尝试使用来自类似问题的建议,例如 Animate a Circle around another circle ,但不幸的是它没有帮助。我尝试寻找可以提供所需功能的 3rd 方模块,但没有找到适合我需要的东西。

我找到了一个有用的 article 来理解 JavaScript 中的圆周运动,但是我很难在 React Native 动画中复制它。我相信在动画循环运动时,我很难理解 Animated APItransform 样式属性的正确用法。


<View style={animationContainer}>
    <Image
      source={require('./images/image.png')}
      style={image}
    />
    <Animated.Image
      source={require('./images/icon.png')}
      style={circlingIcon}
    />
</View>

【问题讨论】:

  • This 就是你要找的东西
  • @CampbellMG 我见过那个,它看起来是一个不错的解决方案,但不是最好的。但我很感激指出这个例子
  • 该解决方案的哪一部分不适合您?
  • 我不喜欢这个解决方案的地方是它可以近似为圆周运动,但不能提供精确的功能相关性。有一个变量snapshot,它定义了您希望在动画中拥有多少帧。我希望找到的是正确插值会导致连续图形/运动的值
  • 您在尝试使用Animated API 创建圆周运动时遇到的问题是您只能访问基本的数学函数(加、除、模等)。这就是为什么此解决方案沿圆形路径而不是精确数字采样值的原因。您可以尝试使用 this 之类的库,其中包含一些更复杂的函数,例如使用泰勒级数的 sin。

标签: javascript react-native animation


【解决方案1】:

我已经为react native circle transform translate animation这个问题发布了一个类似的butter smooth解决方案@

完整代码:


import React, {Component} from 'react';
import {View, Text, Animated, StyleSheet, Easing} from 'react-native';

export default class Circle extends Component {
    constructor() {
        super();
        this.animated = new Animated.Value(0);
        var inputRange = [0, 1];
        var outputRange = ['0deg', '360deg'];
        this.rotate = this.animated.interpolate({inputRange, outputRange});
        outputRange = ['0deg', '-360deg'];
        this.rotateOpposit = this.animated.interpolate({inputRange, outputRange});
    }

    componentDidMount() {
        this.animate();
    }

    animate() {
      Animated.loop(
        Animated.timing(this.animated, {
            toValue: 1,
            duration: 4000,
            useNativeDriver: true,
            easing: Easing.linear,
        }),
      ).start();
    }
    render() {
        const transform = [{rotate: this.rotate}];
        const transform1 = [{rotate: this.rotateOpposit}];
        return (
          <View style={styles.container}>
            <Animated.View style={[styles.item, {transform}]}>
              <Animated.View style={[styles.topItem, {transform: transform1}]}>
                <Text style={styles.text}>Test</Text>
              </Animated.View>
            </Animated.View>
          </View>
        );
    }
 }
 const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    item: {
        position: 'absolute',
        width: 100,
        height: 200, // this is the diameter of circle
    },
    topItem: {
        width: '100%',
        height: 20,
        backgroundColor: 'red',
        position: 'absolute',
        alignItems: 'center',
        justifyContent: 'center',
    },
    text: {
        color: '#fff',
    },
 });

希望对你有帮助..

【讨论】:

    【解决方案2】:

    我从一个问题react native circle transform translate animation 中得到了一个解决方案,并通过在两个不同的函数中分离 Y 和 X 上的坐标插值来稍微重构它。

    interface InterpolatedMotion {
      translateX: Animated.Value;
      translateY: Animated.Value;
    }
    
    interface AnimatedIcon extends InterpolatedMotion {
      animated: Animated.Value;
    }
    
    interface State {
      icon: AnimatedIcon;
    }
    
    const defaultAnimatedIcon = (animatedValue: number): AnimatedIcon => ({
      animated: new Animated.Value(animatedValue),
      translateX: new Animated.Value(0),
      translateY: new Animated.Value(0),
    });
    
    export class Animation extends PureComponent<Props, State> {
      state = {
        icon: defaultAnimatedIcon(0),
      }
    
      constructor(props) {
        super(props);
        let { icon } = this.state;
    
        icon.animated.setValue(0);
    
        const snapshot = 50;
        const radius = 200;
    
        const inOutX = this.interpolateCircularMotionOverX(snapshot, radius);
    
        icon.translateX = coins.animated.interpolate(inOutX);
    
        const inOutY = this.interpolateCircularMotionOverY(snapshot, radius);
    
        icon.translateY = coins.animated.interpolate(inOutY);
      }
    
      componentWillMount(): void {
        this.startAnimation();
      }
    
      startAnimation = (): void => {
        let { icon } = this.state;
    
        icon.animated.setValue(0);
    
        let animations = [
          Animated.timing(
            icon.animated,
            {
              toValue: 1,
              duration: 8000,
              easing: Easing.linear,
            },
          ),
        ];
    
        Animated.loop(
          Animated.parallel(animations),
        ).start(() => {
          icon.animated.setValue(0);
        });
      }
    
      interpolateCircularMotionOverX = (snapshot: number, radius: number) => {
        const inputRange = [];
        const outputRange = [];
        for (let i = 0; i <= snapshot * 2; ++i) {
          const value = i / snapshot;
          const move = Math.sin(value * Math.PI * 2) * radius;
          inputRange.push(value);
          outputRange.push(move);
        }
        return { inputRange, outputRange };
      }
    
      interpolateCircularMotionOverY = (snapshot: number, radius: number) => {
        const inputRange = [];
        const outputRange = [];
        for (let i = 0; i <= snapshot * 2; ++i) {
          const value = i / snapshot;
          const move = -Math.cos(value * Math.PI * 2) * radius;
          inputRange.push(value);
          outputRange.push(move);
        }
        return { inputRange, outputRange };
      }
    
      render(): JSX.Element {
        const { icon } = this.state;
    
        const transformIcon = [
          { translateY: icon.translateY },
          { translateX: icon.translateX },
        ];
    
        return (
            <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
              <View style={{ flex: 1 }}>
                <Animated.Image
                  source={require('./images/coins.png')}
                  style={[Styles.forms.circlingIcon, { transform: transformCoins }]}
                />
              </View>
            </View>
        );
    }
    

    这帮助我为将来的任何圆形动画实例提供了一个灵活且可重复使用的解决方案。

    【讨论】:

    • 我使用了Animated.Image,它在本地工作(开发模式),但是在构建并上传到testflight之后,图像变成了正方形。你有什么偶然的想法吗?
    • 您是否尝试过使用 useNativeDriver : reactnative.dev/blog/2017/02/14/… ?我不确定它是否会帮助你,但值得一试。
    • 是的,还是一样。我所做的是将Animated.Image 更改为Animated.View 并将图像传递给Image 组件并且它可以工作。
    猜你喜欢
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 2021-05-18
    相关资源
    最近更新 更多