[React Native] Animation

2022. 1. 24. 02:24React Native/Basic


1. XY Animation 생성하기

상하좌우로 움직이는 애니메이션에 대해 배워보자. 

 

우선 새로운 프로젝트를 생성한다. 항상 그렇듯 Add folder to workspace 하고 App.js 를 수정하자. src폴더를 새로 만들고 그 안에 Animation01.js 파일을 만든다. Animation01.js는 AnimOne을 export하는데 가로, 세로 100짜리 하늘색 정사각형을 만든다. App.js에서 AnimOn을 import 하고 <AnimOne/>을 뷰에 넣어준다.

 

Animation을 넣어주기 위해 Animation01.js에서 Animated를 import 한다. 그리고 constructor를 하나 만들어 준다. super는 일단 그냥 두고 하늘색 정사각형이 움직이기 시작하는 starting point를 써준다. this.mySquare에 new Animated.ValueXY(0,0)을 써주어 (0,0)을 초기값으로 하여 상하좌우로 움직이는 애니메이션을 만든다. starting point가 있으면 end point도 써줘야 한다.

 

componentDidMount라는 이름의 함수를 만들어주자. 이 함수는 render 함수가 실행된 다음에 호출되는 함수이다. 이름 그래도  컴포넌트가 마운트되었다는 뜻으로 가장 나중에 실행되는 함수이며 ending point를 지정해서 거기로 이동하게끔 해주면 된다. Animated.spring이라는 메소드를 불러올 거고 우리는 mySquare를 움직이도록 할 건데 어디로 움직이도록 할 거냐면 x는 50, y는 300으로 가라고 할 거다. 그리고 start를 걸어서 animation을 트리거링 할 거고 다시 렌더링 되게 한다. 

 

그런데 이대로는 아무것도 실행되지 않는다. render 함수 안에 animation을 실행토록 하는 부분이 피룡하다. <Animated.View>를 넣고 그 안에 원래 만들어둔 <View>를 넣자. <Animated.View>에는 스타일을 줄 건데 left는 mySquare의 x좌표, top은 mySquare의 y좌표로 준다.

 

이렇게 하고 실행하면 잘 실행된다. 그런데 스타일은 이렇게 지정해도 되지만 좀 복잡해서 더 간단히 작성할 수도 있다. mySquare의 getLayout 메소드를 불러오는 것이다.

 

Animation.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.mySquare = new Animated.ValueXY(0, 0);
  }

  componentDidMount() {
    Animated.spring(this.mySquare, {
      toValue: {x: 50, y: 300},
    }).start();
  }
  render() {
    return (
      <Animated.View
        style={this.mySquare.getLayout()}
        //  style={{
        //      left:this.mySquare.x,
        //      top:this.mySquare.y
        //  }}
      >
        <View style={styles.square}></View>
      </Animated.View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

 

App.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import AnimOne from './src/Animation01';
class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <AnimOne />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
});

export default App;

2. XY Animation의 추가 효과 및 Triggering Button 생성

ComponentDidMount 함수를 보면 spring 메소드를 쓰고 있지만 다른 메소드도 있다.

 

spring을 썼을 때는 정사각형이 빨리 움직였지만 timing을 쓰면 천천히 움직이게 할 수 있다.

componentDidMount() {
    Animated.timing(this.mySquare, {
      toValue: {x: 50, y: 300},
      duration: 2000,
      delay: 1500,
    //   easing: Easing.bounce,
    easing:Easing.elastic(3),
    }).start();
  }
duration - 지속시간으로 ms 단위이다.
delay - 딜레이 시간
easing: Easing.bounce - 통통 튀는 효과
easing: Easing.elastic(num) - 괄호 안의 숫자만큼 늘어났다가 ending point에 위치한다.

 

https://reactnative.dev/docs/animated#configuring-animations

 

Animated · React Native

The Animated library is designed to make animations fluid, powerful, and painless to build and maintain. Animated focuses on declarative relationships between inputs and outputs, configurable transforms in between, and start/stop methods to control time-ba

reactnative.dev

위의 사이트는 공식문서로 spring이나 timing 외에도 다양한 method를 배울 수 있다.

 

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.mySquare = new Animated.ValueXY(0, 0);
  }

  componentDidMount() {
    Animated.timing(this.mySquare, {
      toValue: {x: 50, y: 300},
      duration: 2000,
      delay: 1500,
    //   easing: Easing.bounce,
    easing:Easing.elastic(3),
    }).start();
  }
  render() {
    return (
      <Animated.View
        style={this.mySquare.getLayout()}
        //  style={{
        //      left:this.mySquare.x,
        //      top:this.mySquare.y
        //  }}
      >
        <View style={styles.square}></View>
      </Animated.View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

 

버튼을 눌렀을 때 Animation이 트리거 될 수 있도록 하는 방법을 알아보자.

우선 Button을 import 한다. <Animated.View> 아래에 <Button />을 추가하는데 컴포넌트는 <View> 로 감싸져 있어야 하기 때문에 <View> 태그로 감싸준다. Button의 onPress 시에 runAnimation이라는 함수를 호출하는데 이 함수는 정의해줘야 하는 함수인데 그 전에 선언한 mySquare를 state 안에 넣어준다. 그리고 runAnimation 함수는 componentDidMount 함수를 대신하도록 한다. mySquare가 state 안에 정의되어 이 부분을 다 수정해준다.

 

아래 코드와 같이 수정하면 잘 동작한다.

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.state = {
        mySquare: new Animated.ValueXY(0, 0)
    }
  }

  runAnimation = () => {
    Animated.timing(this.state.mySquare, {
      toValue: {x: 50, y: 300},
      duration: 2000,
      delay: 1500,
    //   easing: Easing.bounce,
    easing:Easing.elastic(3),
    }).start();
  }
  render() {
    return (
        <View>
      <Animated.View
        style={this.state.mySquare.getLayout()}
        //  style={{
        //      left:this.mySquare.x,
        //      top:this.mySquare.y
        //  }}
      >
        <View style={styles.square}></View>
      </Animated.View>
      <Button 
        title="Animation Start"
        onPress={this.runAnimation}
      
      />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

여기까지는 XY에 대해서만 animation 효과를 만들었는데 다른 효과에 대해서도 알아보자.


3. 다른 Animation 효과 생성하기

XY 좌표값이 필요한 이동 애니메이션뿐만 아니라 색이나 투명도가 바뀌는 애니메이션도 필요하다. 여기서는 투명도가 변하는 애니메이션을 알아보자.

투명도 - 0~1까지의 값을 가지며 0이 완전 투명하고 1이 완전 불투명한 것이다.

완전 불투명 -> 완전 투명을 만들어보자.

그럼 일단 starting point가 되는 constructor에서 값을 1로 바꿔줘야 하는데 XY 값이 아니므로 그냥 Value를 주고 괄호 안에 1을 주자.

그리고 runAnimation 함수 안에서는 ending point 의 값을 0으로 준다. 그리고 easing 프로퍼티는 없애주자. 또한 <Animated.View>의 스타일은 opcaity:this.state.mySquare로 준다.

 

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.state = {
      mySquare: new Animated.Value(1),
    };
  }

  runAnimation = () => {
    Animated.timing(this.state.mySquare, {
      toValue: 0,
      duration: 2000,
      delay: 1500,
    }).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          // style={this.state.mySquare.getLayout()}
          style={{
            opacity: this.state.mySquare,
          }}>
          <View style={styles.square}></View>
        </Animated.View>
        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

4. Interpolation(Animation 효과 조합)

이번엔 interpolation이라는 2개의 애니메이션 효과를 동시에 보여주는 방법을 알아보자.

지금까지 본 이동과 투명도의 변화를 동시에 줘 보자.

<Animated.View> 안의 style에 property와 interpolate라는 메소드를 추가하자. opacity라는 투명도 애니메이션을 위한 프로퍼티가 선언되어 있으니까 이동하는 애니메이션을 위한 프로퍼티를 추가하자. top에서 mySquare에 interpolate라는 메소드를 호출한다. 그 안에 inputRange라는 프로퍼티와 outputRange라는 프로퍼티가 필요하다.

 

inputRange - contructor 내부와 runAnimation 내부에 선언해둔 프로퍼티의 값이 들어간다.

여기서는 opacity가 inputRange가 된다.

outputRange - 동시에 효과를 주고싶은 프로퍼티의 값이 들어간다. 

여기서는 top이니까 y축 좌표값이 들어갈 것이다. 그런데 하나의 값이 들어가는게 아니라 배열이 들어가서 여러 요소를 담을 수 있는데 starting point와 ending point에서의 값이 들어가게 된다.

 

정사각형이 위에서 아래로 내려오면서 투명해지는 애니메이션을 만든다고 할 때, starting point에서 ending point로 정사각형이 움직이면서 y축 좌표는 0에서 0보다 큰 어떤 값으로 변할 거고 투명도는 1에서 0으로 바뀔 거다. 그래서 1과 0을 요소로 갖는 배열이 inputRange로 들어가고 y축 좌표값인 0과 0보다 큰 어떤 값을 요소로 갖는 배열이 outputRange로 들어가게 될 거다.

 

우선 inputRange부터 넣을 건데 여기에는 주의할 사항이 있다. inputRange에 할당되는 배열은 무조건 작은 숫자부터 큰 숫자 순서대로 넣어줘야 한다. 비록 투명도가 1에서 시작해서 0으로 끝나더라도 inputRange의 배열은 작은 값부터 넣어주는 것이 약속된 규약이다.

 

그리고 outputRange를 채울 때도 주의할 사항이 있다. 바로 inputRange와 outputRange가 서로 대응이 되어야 한다는 것이다. 투명도가 0일 때는 이미 정사각형이 내려와 있는 상태일 거고 투명도가 1일 때는 애니메이션이 시작되는 시점일 거다. 그래서 outputRange에 들어가는 배열의 첫 번째 요소는 0보다 큰 어떤 값이 되고 두 번째 요소는 0이 된다.

 

즉, 위의 설명을 한 문단으로 표현하면 다음 문단이 된다.

 

constructor와 runAnimation 내부에 선언해둔 값은 투명도의 값이다. 그래서 투명도의 값은 inputRange에 해당되는 거고 1과 0을 배열로 넣어줘야 하는데 숫자가 작은 값부터 넣어줘야 한다는 규약이 있어 [0,1]로 넣어줬다. 그리고 outputRange는 프로퍼티를 top으로 설정했으니까 y축 좌표값이 들어가는데 inputRange와 index가 대응되어야 하기 때문에 ending point에서의 y축 좌표값을 첫 번째로 넣어준 것이고 starting point에서의 y축 좌표값을 두 번째 요소로 넣었다.

 

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.state = {
      mySquare: new Animated.Value(1),
    };
  }

  runAnimation = () => {
    Animated.timing(this.state.mySquare, {
      toValue: 0,
      duration: 2000,
      delay: 1500,
    }).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          // style={this.state.mySquare.getLayout()}
          style={{
            opacity: this.state.mySquare,
            top:this.state.mySquare.interpolate({
                inputRange:[0,1],
                outputRange:[700, 0],
            })
          }}>
          <View style={styles.square}></View>
        </Animated.View>
        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

 

 

 

위에서 살펴본 top이라는 프로퍼티는 다르게 표현될 수도 있다.

transform이라는 프로퍼티에서 translateY라는 프로퍼티를 사용하면 top과 동일하게 동작한다.

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.state = {
      mySquare: new Animated.Value(1),
    };
  }

  runAnimation = () => {
    Animated.timing(this.state.mySquare, {
      toValue: 0,
      duration: 2000,
      delay: 1500,
    }).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          // style={this.state.mySquare.getLayout()}
          style={{
            opacity: this.state.mySquare,
            transform: [
              {
                translateY: this.state.mySquare.interpolate({
                  inputRange: [0, 1],
                  outputRange: [700, 0],
                }),
              },
            ],
          }}>
          <View style={styles.square}></View>
        </Animated.View>
        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

 

정사각형을 x축 기준으로 회전시킬 건데 translateY 대신에 rotateX 프로퍼티를 사용하자. 그리고 outputRange는 x축 기준으로 회전시키는 각도값이 들어간다. 투명도가 달라지며 회전 각도도 변화한다.

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.state = {
      mySquare: new Animated.Value(1),
    };
  }

  runAnimation = () => {
    Animated.timing(this.state.mySquare, {
      toValue: 0,
      duration: 2000,
      delay: 1500,
    }).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          // style={this.state.mySquare.getLayout()}
          style={{
            opacity: this.state.mySquare,
            transform: [
              {
                rotateX: this.state.mySquare.interpolate({
                  inputRange: [0, 0.5, 1],
                  outputRange: ['0deg', '180deg','360deg'],
                }),
              },
            ],
          }}>
          <View style={styles.square}></View>
        </Animated.View>
        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

 

이번엔 투명도, 회전, 이동의 세 가지 애니메이션 효과를 동시에 줘보자.

rotateX 말고 translateX 를 추가하면 되는 간단한 일이다.

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.state = {
      mySquare: new Animated.Value(1),
    };
  }

  runAnimation = () => {
    Animated.timing(this.state.mySquare, {
      toValue: 0,
      duration: 2000,
      delay: 1500,
    }).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          // style={this.state.mySquare.getLayout()}
          style={{
            opacity: this.state.mySquare,
            transform: [
              {
                rotateX: this.state.mySquare.interpolate({
                  inputRange: [0, 0.5, 1],
                  outputRange: ['0deg', '180deg','360deg'],
                }),
              },
              {
                translateX: this.state.mySquare.interpolate({
                  inputRange: [0, 0.5, 1],
                  outputRange: [300, 150, 0],
                }),
              },
              
            ],
          }}>
          <View style={styles.square}></View>
        </Animated.View>
        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

 

 

애니메이션 효과는 뷰 뿐만 아니라 텍스트에도 줄 수 있다. 크기가 점점 커지며 파 -> 초 -> 빨의 색으로 변하는 텍스트 효과를 줘보자. 텍스트와 도형은 동시에 애니메이션 효과를 발생한다. 

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimOne extends Component {
  constructor() {
    super();
    this.state = {
      mySquare: new Animated.Value(1),
    };
  }

  runAnimation = () => {
    Animated.timing(this.state.mySquare, {
      toValue: 0,
      duration: 2000,
      delay: 1500,
    }).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          // style={this.state.mySquare.getLayout()}
          style={{
            opacity: this.state.mySquare,
            transform: [
              {
                rotateX: this.state.mySquare.interpolate({
                  inputRange: [0, 0.5, 1],
                  outputRange: ['0deg', '180deg', '360deg'],
                }),
              },
              {
                translateX: this.state.mySquare.interpolate({
                  inputRange: [0, 0.5, 1],
                  outputRange: [300, 150, 0],
                }),
              },
            ],
          }}>
          <View style={styles.square}></View>
        </Animated.View>
        <Animated.Text
          style={{
            fontSize: this.state.mySquare.interpolate({
              inputRange: [0, 0.5, 1],
              outputRange: [40, 30, 20],
            }),
            color: this.state.mySquare.interpolate({
              inputRange: [0, 0.5, 1],
              outputRange: ['red', 'green', 'blue'],
            }),
          }}>
          <Text>Animation Effects</Text>
        </Animated.Text>
        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  square: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
  },
});

export default AnimOne;

5. Animation 효과 순서 정하기 

복수의 도형에 애니메이션을 각각 주는 방법을 알아보자.

src 폴더 내에 새로운 Animation02.js 파일을 만든다. 도형을 만드는 것은 아래 코드를 참고하고 중요한 runAnimation 함수 구현을 봐보도록 하자.



sequence - Animated에 있는 메소드로 애니메이션을 순차적으로 진행시키기 위한 메소드

redSquare는 투명도가 inputRange지만 greenSquare, BlueSquare는 XY좌표가 inputRange이다. red는 timing으로 green, blue는 spring 메소드를 사용한다. start()까지만 하면 실행되지 않는데 Animated View에 스타일을 추가해야하기 때문이다.

red는 opacity, green, blue는 getLayout을 사용한다.

 

실행하게 되면 runAnimation에 있는 애니메이션이 차례로 하나씩 실행되는 것을 볼 수 있다.

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimTwo extends Component {
  constructor() {
    super();
    this.state = {
      redSquare: new Animated.Value(1),
      greenSquare: new Animated.ValueXY(0, 0),
      blueSquare: new Animated.ValueXY(0, 0),
    };
  }

  runAnimation = () => {
    Animated.sequence([
      Animated.timing(this.state.redSquare, {
        toValue: 0,
      }),
      Animated.spring(this.state.greenSquare, {
        toValue: {x: 200, y: 0},
      }),
      Animated.spring(this.state.blueSquare, {
        toValue: {x: 200, y: 400},
      }),
    ]).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          style={{
            opacity: this.state.redSquare,
          }}>
          <View style={styles.redSquare}></View>
        </Animated.View>
        <Animated.View style={this.state.greenSquare.getLayout()}>
          <View style={styles.greenSquare}></View>
        </Animated.View>
        <Animated.View style={this.state.blueSquare.getLayout()}>
          <View style={styles.blueSquare}></View>
        </Animated.View>

        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  redSquare: {
    width: 100,
    height: 100,
    backgroundColor: 'red',
  },
  greenSquare: {
    width: 100,
    height: 100,
    backgroundColor: 'green',
  },
  blueSquare: {
    width: 100,
    height: 100,
    backgroundColor: 'blue',
  },
});

export default AnimTwo;

 

이번엔 동시에 애니메이션이 실행되게 만들어보자. runAnimation 함수 내부를 수정하면 되는데 Animated.parallel 메소드 안에 동시에 실행하고 싶은 애니메이션을 배열로 넣게 되면 동시에 수행된다. 아래 코드에서는 red가 수행된 뒤에 green, blue가 동시에 수행됐다.

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
  Animated,
  Easing,
  Button,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

class AnimTwo extends Component {
  constructor() {
    super();
    this.state = {
      redSquare: new Animated.Value(1),
      greenSquare: new Animated.ValueXY(0, 0),
      blueSquare: new Animated.ValueXY(0, 0),
    };
  }

  runAnimation = () => {
    Animated.sequence([
      Animated.timing(this.state.redSquare, {
        toValue: 0,
      }),
      Animated.parallel([
        Animated.spring(this.state.greenSquare, {
            toValue: {x: 200, y: 0},
          }),
          Animated.spring(this.state.blueSquare, {
            toValue: {x: 200, y: 400},
          }),
      ])
      
    ]).start();
  };
  render() {
    return (
      <View>
        <Animated.View
          style={{
            opacity: this.state.redSquare,
          }}>
          <View style={styles.redSquare}></View>
        </Animated.View>
        <Animated.View style={this.state.greenSquare.getLayout()}>
          <View style={styles.greenSquare}></View>
        </Animated.View>
        <Animated.View style={this.state.blueSquare.getLayout()}>
          <View style={styles.blueSquare}></View>
        </Animated.View>

        <Button title="Animation Start" onPress={this.runAnimation} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  redSquare: {
    width: 100,
    height: 100,
    backgroundColor: 'red',
  },
  greenSquare: {
    width: 100,
    height: 100,
    backgroundColor: 'green',
  },
  blueSquare: {
    width: 100,
    height: 100,
    backgroundColor: 'blue',
  },
});

export default AnimTwo;

 

추가적인 것들은 공식문서를 보며 개인적으로 더 알아보는 것을 추천한다.


참고 자료

https://www.inflearn.com/course/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EA%B8%B0%EC%B4%88/dashboard

 

iOS/Android 앱 개발을 위한 실전 React Native - Basic - 인프런 | 강의

Mobile App Front-End 개발을 위한 React Native의 기초 지식 습득을 목표로 하고 있습니다. 진입장벽이 낮은 언어/API의 활용을 통해 비전문가도 쉽게 Native Mobile App을 개발할 수 있도록 제작된 강의입니다

www.inflearn.com