1

I'm new to react-native and need some help with Animate.

Goal: to animate Image, so that it looks like its slowly breathing.(getting a little larger then smaller, then back again, constantly, like someone breathing in and out)

My images are stored in an array, inside newOrder() method:

 newOrder(timeAsProp) {
    const hour = timeAsProp.slice(0, 2);
    let returnValue = [];
    const yud = <Image key="yud" source={require('./img/yud.png')} style={Style.image} />;
    const hey1 = <Image key="hey1" source={require('./img/hey1.png')} style={Style.image} />;
    const vav = <Image key="vav" source={require('./img/vav.png')} style={Style.image} />;
    const hey2 = <Image key="hey2" source={require('./img/hey2.png')} style={Style.image} />;
     return (
<View style={Style.displayContainer}>{returnValue}</View>
);

called in the render method, like this:

{this.newOrder(parsedTime)}

its four seperate images, which are rendered and displayed together on one line. it looks like this:

letters being rendered to one word:

its important that the Image as a whole, should be breathing together in unison, and not each image on its own. heres a screen pic so you see what the image looks like, if that will help you understand the best method to make it look alive:

edit: something that would add to the animation i think, would be two things: 1)size getting larger and smaller 2)actual color patch on the letters slightly moving, maybe closer and further, like zooming in and out or something like that. i think those two together would make the breathing 3d.

so im interested in hearing peoples opinions how to do this... thnks!

2 Answers2

3

Use a sequence of animations in a loop. In this example I am breathing a text. First change the opacity from 1 to 0, then, change the opacity back to 1. You can use this principle to change other properties, like width and height.

import React, {Component} from 'react'
import {
  Animated,
  Easing
} from 'react-native'

export default class MyComponent extends Component {

  constructor(props) {
    super(props);
    this.state = {
      opacity: new Animated.Value(1)
    }
  }

  componentDidMount() {
    Animated.loop(
      Animated.sequence([
        Animated.timing(this.state.opacity, {
          toValue: 0,
          duration: 1000,
          ease: Easing.linear,
          useNativeDriver: true
        }),
        Animated.timing(this.state.opacity, {
          toValue: 1,
          duration: 1000,
          ease: Easing.linear,
          useNativeDriver: true
        })
      ])
    ).start();
  }

  render() {
    return(
      <Animated.View style={{opacity: this.state.opacity}}>
        <Text>I'm breathing</Text>
      </Animated.View>
    );
  }
}
Rayron Victor
  • 2,398
  • 1
  • 25
  • 25
2

So for an infinite animation (that you can stop on your own), you can set the width and height of all of the images to the same interpolated Animated value. To generate a breathing effect, one possible way to do this is to tie two animation functions together with one increasing and the other decreasing. For example:

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

const AnimatedImage = Animated.createAnimatedComponent(Image);

export default class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      size: new Animated.Value(1)
    }
  }

  componentDidMount () {
    this._loopAnimationUp();
  }

  // The animation functions. Initial and end values can be anything (not just 1, 10, but remember to use the same value and flip them:
  _loopAnimationUp() {
    this.state.size.setValue(1);
    Animated.timing(this.state.size, {
      toValue: 10,
      duration: 5000,
      easing: Easing.linear
    }).start((o) => {
      if (o.finished) {
        this._loopAnimationDown();
      }
    });
  }

  _loopAnimationDown() {
    this.state.size.setValue(10);
    Animated.timing(this.state.size, {
      toValue: 1,
      duration: 5000,
      easing: Easing.linear
    }).start((o) => {
      if (o.finished) {
        this._loopAnimationUp();
      }
    });
  }

  render() {
    const size = this.state.size.interpolate({
      inputRange: [1, 10],
      outputRange: [10, 50],
      extrapolate: 'clamp',
    });

    return (
      <View style={styles.container}>
        <AnimatedImage
          style={[styles.image, {
            width: size,
            height: size,
          }]}
          source={{uri: 'http://placekitten.com/g/200/200'}}
        />
        <AnimatedImage
          style={[styles.image, {
            width: size,
            height: size,
          }]}
          source={{uri: 'http://placekitten.com/g/200/200'}}
        />
        <AnimatedImage
          style={[styles.image, {
            width: size,
            height: size,
          }]}
          source={{uri: 'http://placekitten.com/g/200/200'}}
        />
        <AnimatedImage
          style={[styles.image, {
            width: size,
            height: size,
          }]}
          source={{uri: 'http://placekitten.com/g/200/200'}}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    flexDirection: 'row',
  },
  image: {
    justifyContent:'center',
    backgroundColor:'transparent'
  },
});

If you need to later stop the animation, you can use:

this.state.size.stopAnimation();

You can see a working implementation of it here using placeholder images.

For the more math inclined, there is probably a way to accomplish this with a single looping animation and using interpolation in a more complex manner.

Michael Cheng
  • 9,644
  • 6
  • 46
  • 48
  • thnks! see edit above: something that would add to the animation i think, would be two things: 1)size getting larger and smaller 2)actual color patch on the letters slightly moving, maybe closer and further, like zooming in and out or something like that. i think those two together would make the breathing 3d. any ideas? – Simcha Binyamin Katsof Apr 02 '17 at 18:35
  • @SimchaBinyaminKatsof I've edited it to show a working implementation and a link to the snack where you can see it working. It does #1, but I'm not quite sure I understand what you are trying to do in #2. – Michael Cheng Apr 02 '17 at 19:00
  • thnks so much! 1)i would like the 'breathing' to be much more subtle. like just moving up and down a few milimeters from origional size. which values do i edit to do that? 2)what i meant by #2: im just trying to figure out some way to make the 'breathing' more 3D, and not 2D. so the way it is currently, it gets larger and smaller just in a 2nd dimension.but i would want some way to have it appear to be 3d also. like when a persons chest moves up and down when they breath. i can compare it to the old screen savers win XP used to have, with a magnifying ball that rolled around – Simcha Binyamin Katsof Apr 03 '17 at 09:58
  • @SimchaBinyaminKatsof For #1, edit outputRange in interpolate. I suggest reading up on how animations work in react native. Specifically the section on [interpolate](https://facebook.github.io/react-native/docs/animations.html#interpolation). – Michael Cheng Apr 03 '17 at 14:34
  • @SimchaBinyaminKatsof For #2, I think I get what you're saying now. That's something outside of my field of knowledge though as it deals more with 2D/3D animation rather than anything react native specific. You should tag the question with _animation_ and do some research into how that specific effect is implemented in general. Or ask a separate question about how that effect is usually implemented. Then try to implement it in react native. If you post/edit in pseudocode for the effect, I can offer advice on how to implement it. – Michael Cheng Apr 03 '17 at 14:39
  • thnks so much for all the help. i tried implementing this today into my code, and really couldnt figure out where to put each thing.could you help me a bit more with that? for example regarding this part: `const AnimatedImage = Animated.createAnimatedComponent(Image);` should i have 4 of these, one for each of my images? also everything else, i couldnt figure out what to plug in where,since my actual image rendering is done above the render method, and i only call it in the render method. `newOrder(timeAsProp)` – Simcha Binyamin Katsof Apr 03 '17 at 15:48
  • @SimchaBinyaminKatsof The `const AnimatedImage` is just a shorthand for making a reusable animated component; this only needs to be defined once. `AnimatedImage` is the component that you will be using to render an Animated image, so you will have four of those. As for where to place the code, that's hard to answer without knowing what your code base looks like. From the sounds of it, you don't appear to have a full grasp of how React Native works so my best advice is to go through a tutorial like [this](http://www.reactnativeexpress.com) to better understand how to structure your code. – Michael Cheng Apr 04 '17 at 23:14