Search code examples
react-nativereact-animated

React Native Animated API - combine translate and rotation


enter image description here

Encountered this issue recently when I work with react native animated API.

As the image shows, a card component is positioned at top left corner, its flip animation state is controlled by the rotateY value, moving animation is controlled by translateX and translateY values.

It seems the rotation pivot point always been set to the card's original position. After the card has been moved (changing the translateX and translateY value), the card flip rotation animates reference its original position.

It there a way to adjust the rotation pivot point? Alternatively, is there a way to animate component's position instead of translation? Thanks.


Solution

  • Got it working finally. Turns out you can animate the component position change without using the translate property, by adding a listener to the animated value and updating the component state accordingly:

    1. in the constructor, setup card component initial position and cardPos animated value.

    2. in the componentDidMount function, attach listeners to the animated values. when animated values change, update the component state.

    3. in the render function set the component root value style to position:"absolute" and actual position sync to the values in component's state.

    constructor(props){
      super(props);
      // set card initial position as component state
      this.state = {
          cardPosX: this.props.position.x,
          cardPosY: this.props.position.y
      };
      this.flipAnimatedValue = new Animated.Value(
          this.props.isFacingUp ? 180 : 0
        );
      this.flipAnimatedInterpolate = this.flipAnimatedValue.interpolate({
        inputRange: [0, 90, 180],
        outputRange: ["0deg", "90deg", "0deg"]
      });
      // create animated value for card Position X and Y
      this.cardPosXAnimatedValue = new Animated.Value(this.props.position.x);
      this.cardPosYAnimatedValue = new Animated.Value(this.props.position.y);
    }
    
     componentDidMount() {
        // addListener for cardPos Animated Value
        // when animated values change, update the component state
        this.cardPosXAnimatedValue.addListener(({ value }) => {
          this.setState({ cardPosX: value });
        });
        this.cardPosYAnimatedValue.addListener(({ value }) => {
          this.setState({ cardPosY: value });
        });
     }
     
     render(){
      return (
         <View
              style={{
                width: this.cardWidth,
                height: this.cardHeight,
                position: "absolute",
                top: this.state.cardPosY, //card position sync with animated value
                left: this.state.cardPosX
              }}
            >
            ... //child components
         </View>
      );
     }