reactjsreact-nativereact-animatedreact-animations

React Native Animated to scale an image


I have 2 issues with the Animated API.

1st: I am able to show the Image from left to right with the following code. I want to scale the Image from position X=40 (leftPadding), Y=100(topPadding), height:20, width:20 to X=20, Y=10, height:250, width:300. How do I achieve this?

My code:

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

class MyTestComp extends Component {
  componentWillMount() {
    this.animatedValue = new Animated.Value(0);
  }
  buttonPress(){
  this.animatedValue.setValue(0);
    Animated.timing(this.animatedValue,{
      toValue:1,
      duration:1000,
      Easing: Easing
    }).start()
  }

  render() {

    const translateX = this.animatedValue.interpolate({
      inputRange: [0, 1],
      outputRange: [-500, 1]
    })

    const transform = [{translateX}];

    return (
      <View>
        <Text>MyTestComp</Text>
        <Animated.View style={transform}>
        <Image
          source={require('./assets/17.jpg')}
          style={{width:300, height:250}}
        />
        </Animated.View>
        <View style={{marginTop:10}}>
          <Button title="Click Me" onPress={()=> this.buttonPress()} />
        </View>
      </View>
    );
  }
}


export default MyTestComp;

2nd: Everytime I run the animation, I'm getting an exception:

enter image description here

I'm not able to find any documentation on this. How do I use the transform prop.

Many thanks.


Solution

  • I think this is what you want:

    enter image description here

    The animation is actually very smooth, doesn't look so in the GIF because the GIF is 4 Frames Per Second. Here is the code (Since your numbers are all constants, I just hard coded all of them in the below code):

    import React, { Component } from 'react'
    import { Animated, View, TouchableOpacity, Easing,Text} from 'react-native'
    
    const backgroundImage = require('....')
    
    class App extends Component {
        constructor(props) {
            super(props)
            this.animatedValue = new Animated.Value(0)
        }
    
        handleAnimation = () => {
            Animated.timing(this.animatedValue, {
                toValue: 1,
                duration: 1000,
                easing: Easing.ease
            }).start()
        }
    
        render() {
            return (
                <View style={{ flex: 1 }}>
                    <TouchableOpacity onPress={this.handleAnimation}>
                        <Text>
                           Transform Image
                        </Text>
                    </TouchableOpacity>
                    <Animated.Image
                        source={backgroundImage}
                        resizeMode='cover'
                        style={{
                            position: 'absolute',
                            left: 40,
                            top: 100,
                            height: 20,
                            width: 20,
                            transform: [
                                {
                                    translateX: this.animatedValue.interpolate({
                                        inputRange: [0, 1],
                                        outputRange: [0, 120]
                                    })
                                },
                                {
                                    translateY: this.animatedValue.interpolate({
                                        inputRange: [0, 1],
                                        outputRange: [0, 25]
                                    })
                                },
                                {
                                    scaleX: this.animatedValue.interpolate({
                                        inputRange: [0, 1],
                                        outputRange: [1, 15]
                                    })
                                },
                                {
                                    scaleY: this.animatedValue.interpolate({
                                        inputRange: [0, 1],
                                        outputRange: [1, 12.5]
                                    })
                                }
                            ]
                        }}
                    />
                </View>
            )
        }
    }
    
    export default App
    

    Some explanation:

    1. After the animation, image's width becomes 300, which is 280 pixels larger, since the image scales up from the center, therefore, the image's x coordination has left shifted 140 px, or -140 px, And we want the x coordinate to left shift only 20 px, hence, we should right shift it 120 px, that's why the output range of x is [0, 120]

    2. Same reason why y's output range is [0, 25]

    3. width is now 300 compared to before 20, which is 15 times larger

    4. height is now 250 compared to before 20, which is 12.5 times larger