Search code examples
javascriptreactjsreact-nativereact-animated

react native animating multiple views as a circle


I want 2 views which transform like a circle with no rotation at the same time. The first view starts at the top and the second view at the bottom. I already asked how to do it with one view. I dont get it run with two views. Question Before

enter image description here

//import liraries
import React, { Component } from 'react';
import { View, Text, StyleSheet, Animated, Button, TouchableOpacity } from 'react-native';

// create a component
export default class App extends Component {
  constructor() {
      super()
      this.animated = new Animated.Value(0);
      this.animated2 = new Animated.Value(0);

      var range = 1, snapshot = 50, radius = 100;
      /// translateX
      var inputRange = []
      var outputRange = [] 
      var outputRange2 = []
      for (var i=0; i<=snapshot; ++i) {
          var value = i/snapshot;
          var move = Math.sin(value * Math.PI * 2) * radius;
          inputRange.push(value);
          outputRange.push(move);
          outputRange2.push(-move);
      }
      translateX = this.animated.interpolate({ inputRange, outputRange });
      translateX2 = this.animated2.interpolate({inputRange, outputRange2})

      /// translateY
      var inputRange = [] 
      var outputRange = []
      var outputRange2 = []
      for (var i=0; i<=snapshot; ++i) {
          var value = i/snapshot;
          var move = -Math.cos(value * Math.PI * 2) * radius;
          inputRange.push(value);
          outputRange.push(move);
          outputRange2.push(-move);
      }
      translateY = this.animated.interpolate({ inputRange, outputRange });
      translateY2 = this.animated2.interpolate({inputRange, outputRange2})

  }

    animate() {
      this.animated.setValue(0)
      Animated.timing(this.animated, {
        toValue: 1,
        duration: 10000,
      }).start();
      this.animated2.setValue(0)
      Animated.timing(this.animated2, {
        toValue: 1,
        duration: 10000,
      }).start();
    }


    render() {
      //const transform = [{ translateY: this.translateY }, {translateX: this.translateX}];
      return (
        <View style={styles.container}>
          <Animated.View style={
            [{ transform: [{ translateY: translateY }, {translateX: translateX}] }]}>
            <TouchableOpacity style={styles.btn}>
              <Text>hallo</Text>
            </TouchableOpacity>
          </Animated.View>
          <Animated.View style={
            [{ transform: [{ translateY: translateY2 }, {translateX: translateX2}] }]}>
            <TouchableOpacity style={styles.btn}>
              <Text>hallo</Text>
            </TouchableOpacity>
          </Animated.View>
          <Button title="Test" onPress={() => { 
            this.animate() 
            }} />
        </View>
      );
    }
  }

  // define your styles
  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: '#2c3e50',
    },
    btn2: {
      justifyContent: 'center',      
      alignItems: 'flex-end',
      alignSelf: 'flex-end'
    },
    btn: {
      backgroundColor: 'red',
      justifyContent: 'center',
      alignItems: 'center',
      width: 50,
    }
  });

Solution

  • To make multiple animations at the same time, just create multiple Animated.Value, or interpolate from it multiple times.

    The moving track is about calculate translateX and translateY with Trigonometric Function.

    translateX is corresponding to Math.sin(), and translateY is corresponding to Math.cos().

    Code for option two (interpolate from one Animated.Value multiple times):

    export class App extends Component {
        constructor() {
            super()
            this.animated = new Animated.Value(0);
    
            var range = 1, snapshot = 50, radius = 100;
    
            /// translateX
            var inputRange = [], outputRange = [];
            for (var i=0; i<=snapshot; ++i) {
                var value = i/snapshot;
                var move = Math.sin(value * Math.PI * 2) * radius;
                inputRange.push(value);
                outputRange.push(move);
            }
            this.translateX = this.animated.interpolate({ inputRange, outputRange });
    
            /// translateY
            var inputRange = [], outputRange = [];
            for (var i=0; i<=snapshot; ++i) {
                var value = i/snapshot;
                var move = -Math.cos(value * Math.PI * 2) * radius;
                inputRange.push(value);
                outputRange.push(move);
            }
            this.translateY = this.animated.interpolate({ inputRange, outputRange });
    
            /// translateX2
            var inputRange = [], outputRange = [];
            for (var i=0; i<=snapshot; ++i) {
                var value = i/snapshot;
                var move = Math.sin((value + 1/2) * Math.PI * 2) * radius;
                inputRange.push(value);
                outputRange.push(move);
            }
            this.translateX2 = this.animated.interpolate({ inputRange, outputRange });
    
            /// translateY2
            var inputRange = [], outputRange = [];
            for (var i=0; i<=snapshot; ++i) {
                var value = i/snapshot;
                var move = -Math.cos((value + 1/2) * Math.PI * 2) * radius;
                inputRange.push(value);
                outputRange.push(move);
            }
            this.translateY2 = this.animated.interpolate({ inputRange, outputRange });
    
        }
    
          animate() {
            this.animated.setValue(0)
            Animated.loop(
                Animated.timing(this.animated, {
                    toValue: 1,
                    duration: 1000,
                  })
            ).start();
          }
    
    
          render() {
            const transform = [{ translateY: this.translateY }, {translateX: this.translateX}];
            const transform2 = [{ translateY: this.translateY2 }, {translateX: this.translateX2}];
            return (
              <View style={styles.container}>
                <Animated.View style={[{ transform }]}>
                  <TouchableOpacity style={styles.btn}>
                    <Text>hallo</Text>
                  </TouchableOpacity>
                </Animated.View>
    
                <Animated.View style={[{ transform: transform2 }]}>
                  <TouchableOpacity style={styles.btn}>
                    <Text>hallo</Text>
                  </TouchableOpacity>
                </Animated.View>
    
                <Button title="Test" onPress={() => { 
                  this.animate() 
                  }} />
              </View>
            );
          }
        }
    
        // define your styles
        const styles = StyleSheet.create({
          container: {
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: '#2c3e50',
          },
          btn: {
            backgroundColor: 'red',
            justifyContent: 'center',
            alignItems: 'center',
            width: 50,
          }
        });
    

    Result:

    enter image description here