LoginSignup
3

More than 1 year has passed since last update.

React Nativeのアニメーションことはじめ

Last updated at Posted at 2021-08-20

react-native-reanimated(reanimated2)とreact-native-gesture-handlerを用いたアニメーションについて、概念の理解などに苦しんだので備忘録。
素人ですので、間違えなどあればご指摘いただけると幸いです。

一番簡単なアニメーション(PanGesture)

import * as React from "react";
import { StyleSheet, View } from "react-native";
import Animated, {
  useAnimatedGestureHandler,
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from "react-native-reanimated";
import {
  PanGestureHandler,
  PanGestureHandlerGestureEvent,
} from "react-native-gesture-handler";


interface ContextInterface {
  translateX: number;
  translateY: number;
};

export default function PanGestureScreen() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  const panGestureEvent = useAnimatedGestureHandler<
    PanGestureHandlerGestureEvent,
    ContextInterface
  >({
    onStart: (event, context) => {
      // contextはgesture中に自在にアクセスできるobject 自分が必要な値をstart時にもたせて置くことで、他のeventの際にその値を参照できる
      context.translateX = translateX.value;
      context.translateY = translateY.value;
    },
    onActive: (event, context) => {
   // gesutreスタート時の位置とtransltaion分の位置を足して現在の位置を算出する
      translateX.value = event.translationX + context.translateX;
      translateY.value = event.translationY + context.translateY;
    },
    onEnd: (event) => {}
  });

  const reanimatedStyle = useAnimatedStyle(() => {
    return {
      transform: [
        {
          translateX: translateX.value,
        },
        {
          translateY: translateY.value,
        },
      ],
    };
  });

  return (
    <View style={styles.container}>
      <PanGestureHandler onGestureEvent={panGestureEvent}>
        // 以下の四角いViewがアニメーションする
        <Animated.View style={[styles.square, reanimatedStyle]} />
      </PanGestureHandler>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  circle: {
    width: 200,
    height: 200,
    alignItems: "center",
    justifyContent: "center",
    borderRadius: 100,
    borderWidth: 5,
    borderColor: "rgba(0,0,256,0.5)",
  },
});


動作例

pangesture.gif

react native で gesture & animationを実装するために必要な概念

①JS thread と UI thread

react nativeでは大きく分けて上記の2つのthreadを考えることができる
UI thireadは60frames(コマ送り)/1秒 で動いており、JS threadとは非同期でやり取りしている。
このやり取りの中で、UI threadからanimationに関するframeの要求がJS threadに送られ、それをresponse するという動作が16.6(=1/60)ミリ秒以内に完結しないと、frame dropがおきてアニメーションがぎこちなくなってしまう(UXが低下してしまう)。
このような問題の対策としてreact-native-reanimatedとreact-native-gesture-handlerから提供されるapiがある。これらのapiは
全てのgestureとanimataionに関するメソッドなどをUI側で宣言して、2つのthreadでのやり取りをなくす
つまり、animationのeventが生じるだけではUI threadとJS threadは疎通しないのでスムーズにアニメーションできる

②よく出てくる用語やapiの考え方

useSharedValue
UI thread と JS thread でshareできる値を提供するapi js thread(react native)から由来するアニメーションを可能にする
worklet
関数にこのディレクティブを指定すると その関数がコンパイルされてUI thireadに送られ、UI thiread側で実行できるようになる
interpolate (和訳: 補間)
shared valueをアニメーションしやすい値に補間するためのapi e.g. shared valueが0から1にアニメーションし、interpolateによって0から360に補間してrotateの角度をアニメーションさせる 他にも rgba表記のcolorな どもアニメーションせさられる。

参考

公式(reanimated2): https://docs.swmansion.com/react-native-reanimated/
公式(gesture-handler): https://docs.swmansion.com/react-native-gesture-handler/
worklet : https://www.youtube.com/watch?v=6dDpggVnZPo
william's tutorial at freeCodeCamp.org : https://www.youtube.com/watch?v=wEVjaXK4sYQ
https://chrizog.com/react-native-rotation-anchor-point

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3