ReactJS:AnimationValue.interpolate 用于 sin 和 cos

ReactJS: AnimationValue.interpolate for sin and cos

我正在尝试为 ReactJS 原生组件设置动画,使其以圆形方式围绕一个点连续运行。基本上,我需要一个不断增加的计时器,我可以用它来将 X、Y 坐标设置为 {x: r * Math.sin(timer), y: r * Math.cos(timer)}

我找到了这个指南,其中包含一些关于插值的非常有用的信息,但我仍然没有取得任何成功:

http://browniefed.com/react-native-animation-book/INTERPOLATION.html

如何像这样更新组件的位置?

附加问题:如何使动画连续?

我最终想出了一个方法来做到这一点,虽然它并不理想,但我会很感激任何其他输入。这是我的代码:

class MyComponent extends Component {
    constructor(props) {
        super(props);

        this.state = {
            rotation: new Animated.Value(0),
            pos: new Animated.ValueXY()
        }
    }

    componentDidMount() {
        this.animate(10000);
    }

    animate(speed) {
        Animated.parallel([
            Animated.timing(this.state.rotation, {
                toValue: 360,
                duration: speed,
                easing: Easing.linear
            }),
            Animated.timing(this.state.pos, {
                toValue: {x: 360, y: 360},
                duration: speed,
                easing: Easing.linear,
                extrapolate: 'clamp'
            })
        ]).start(() => {
            // Cycle the animation
            this.state.rotation.setValue(0);
            this.state.pos.setValue({x: 0, y: 0});
            this.animate(speed);
        });
    }

    render() {
        let range = new Array(360);
        for (let i = 0; i < 360; i++) {
            range[i] = i;
        }

        var radius = 51,
            offset = 40;

        return (
            <View style={this.props.style}>
                <Animated.View style={{position: 'absolute', transform: [
                    // Map the inputs [0..360) to x, y values
                    {translateX: this.state.pos.x.interpolate({
                        inputRange: range,
                        outputRange: range.map(i => offset + radius * Math.cos(i * Math.PI / 180))
                    })},
                    {translateY: this.state.pos.y.interpolate({
                        inputRange: range,
                        outputRange: range.map(i => offset - radius * Math.sin(i * Math.PI / 180))
                    })},
                    {rotate: this.state.rotation.interpolate({
                        inputRange: [0, 360],
                        outputRange: ['360deg', '0deg']
                    })}
                ]}}>
                    <Image source={require('image.png')}/>
                </Animated.View>
            </View>
        )
    }
}

基本上,我使用插值函数将 Animated.Value pos 映射到我的函数的所有 360 度结果。我认为这可以通过使用一种映射函数而不是插值函数来改进。有谁知道有没有?

由于react-native插值不支持函数回调,我做了一个辅助函数:

function withFunction(callback) {
    let inputRange = [], outputRange = [], steps = 50;
    /// input range 0-1
    for (let i=0; i<=steps; ++i) {
        let key = i/steps;
        inputRange.push(key);
        outputRange.push(callback(key));
    }
    return { inputRange, outputRange };
}

将动画应用到 translateX 和 translateY:

transform: [
{
   translateX:
      this.rotate.interpolate(
         withFunction( (value) => Math.cos(Math.PI*value*2) * radius )
      )
},
{
   translateY:
      this.rotate.interpolate(
         withFunction( (value) => Math.sin(Math.PI*value*2) * radius )
      )
},
]

视觉结果:

为了使动画连续,我做了这样的事情:

rotate = new Animated.Value(0);

componentDidMount() {
    setInterval( () => {
        let step = 0.05;
        let final = this.rotate._value+step;
        if (final >= 1) final = 0;
        this.rotate.setValue(final);
    }, 50);
}