メインコンテンツまでスキップ

React Native Animation

· 約8分

React Native Animation

React Nativeには2種類のAnimationがあるようです。

  1. Animated API
  2. LayoutAnimation API

今回は Animated をAPI を使ってみたいと思います。

コンポーネントに Animation を適用する手順

コンポーネントに Animation を適用する手順を大まかに5つのステップにまとめると以下になります。

ヒント
  1. Animated.Value で変化させたい値を定義する
  2. 値の変化を定義する
  3. Animation を開始する
  4. View の代わりに Animated.View を使う
  5. styleAnimated.Value を設定する

1. Animated.Value で変化させたい値を定義する

ヒント

new Animated.Value で 変化させたい値(媒介変数的なもの)を定義する。

まずは変化させたい値を定義します。ここでは x を作っています。

const x = useRef(new Animated.Value(0)).current;

この x は初期値に 0 が設定されています。

後で x の値の変化に従い style を変化させてコンポーネントを Animation させます。

2. 値の変化を定義する

ヒント

Animated.timing 関数でCompositeAnimation のインスタンスを生成する。

x の現在の値(最初は初期値)をどこまで変化させるのか、変化に要する時間、一様に変化させるのか等を決めます。

ここでは、x を10秒間で 0 から 1 まで変化する CompositeAnimation のインスタンスを生成します。 CompositeAnimation は1回の Animation につき1回定義する ようにします。普通にコンポーネントの中で定義するとレンダリングされる度にCompositeAnimationが生成されてしまいます。これを回避するために useEffect 等で必要な時だけ生成するようにしましょう。

以下の例では、useEffectx が生成された時(つまり初回レンダリング時)のみ CompositeAnimation を生成するようにしています。

useEffect(() => {
const compositAnimation = Animated.timing(
x,
{
toValue: 1,
duration: 10000,
}
);
}, [x])

ここで注意したいのが、 CompositeAnimation を生成しただけでは、x の変化は開始されません。 CompositeAnimation のメソッド start 関数を呼び出すと x の変化が開始します。

ヒント

Animated.timing の仕様

値をeasing function に従って変化させる CompositeAnimation を生成する関数。

timing: (value: AnimatedValue | AnimatedValueXY, config: TimingAnimationConfig) => CompositeAnimation;

TimingAnimationConfig

変数説明
toValuenumber
AnimatedValue
{ x: number; y: number }
AnimatedValueXY
AnimatedInterpolation
変化後の値
easing(value: number) => numberパラメータの変化曲線。Easing function.
Default: Easing.inOut
Easing.ease, Easing.linearなどがある。
durationnumber変化する時間(ms)。Default: 500
delaynumber変化開始するまでの時間(ms)。Default: 0
isInteractionbooleanDefault: true
useNativeDriverbooleanDefault: false

3. Animation を開始する

Animation の開始:

ヒント

compositAnimation.start()

以下のコードは x が作成された時(つまり最初のレンダリング時)だけ Animation が開始されます。useEffect の依存変数が x なので、x が変更されたときのみ compositeAnimation.start() が呼ばれますが、xAnimated.Value のインスタンスの参照なので初回レンダリング時に生成されて以降は変化しないからです。

ちなみに一度実行された compositeAnimation はもう一度 start しても何も起きないので注意が必要です。

useEffect(() => {
const compositeAnimation = ...;
compositeAnimation.start();
}, [x])

Animation を開始するタイミングをずらしたい場合は、何らかのフラグを用意する必要があります。フラグを状態に保存しておき、そのフラグを変化させることで Animation を開始することができます。

以下のコードは flagtrue になったら Animation が開始する例です。

useEffect(() => {
if (flag) { // flagがtrueになったら開始する
const compositeAnimation = ...;
compositeAnimation.start();
}
}, [x, flag])

以下のようにするとフラグが変化する度に何度も Animation が開始されます。

useEffect(() => {
const compositeAnimation = ...;
compositeAnimation.start();
}, [x, flag])

4. Viewの代わりにAnimated.Viewを使う

変化する Animated.ValueViewstyle に設定して Animation を実現するのですが、通常の View コンポーネントの style には Animated.Value を使用することはできません。以下のように Animated.View を使用します。

<Animated.View>
...
</Animated.View>

5. styleAnimated.Valueを設定する

最後に Animated.ValuestyleAnimated.Value を設定します。以下の例では、opacityx を設定しています。opacity が一定時間で 0 から 1 に変化します。

<Animated.View style={{ opacity: x }}>

複数のAnimationを順番に実行させたり、同時に実行させたりする

順番に実行:

Animated.sequence([
Animated.timing(...),
Animated.decay(...),
Animated.delay(...),
Animated.spring(...),
...
]);

同時に実行:

Animated.parallel([
Animated.timing(...),
Animated.decay(...),
Animated.delay(...),
Animated.spring(...),
...
]);

sequenceparallel を組み合わせる:

Animated.sequence([
...,
Animated.parallel([
...,
]),
...
]);

Animated.Valueの演算:

演算説明
Animated.add足し算
Animated.subtract引き算
Animated.divide割り算
Animated.multiply掛け算
Animated.modulo剰余

Interpolation

interpolateメソッドを使うと Animated.Value の変化に連動する値を作成することができます。以下の例では x0 から1 まですると、traslateY150 から0 まで変化します。

const x = useRef(new Animated.Value(0)).current;    
useEffect(() => {
Animated.timing(
x,
{
toValue: 1,
duration: 10000,
}
).start();
}, [x])
style={{
opacity: x,
transform: [{
translateY: x.interpolate({
inputRange: [0, 1],
outputRange: [150, 0] // 0 : 150, 0.5 : 75, 1 : 0
}),
}],
}}

変化の範囲はいくつも指定することができます。

value.interpolate({
inputRange: [-300, -100, 0, 100, 101],
outputRange: [300, 0, 1, 0, 0]
});

数字だけではなく、角度等を表現する文字列もサポートしています。

      value.interpolate({
inputRange: [0, 360],
outputRange: ['0deg', '360deg']
});

Animation の終了を検知する

CompositeAnimationstart の引数に Animation の終了に呼ばれるコールバックを渡すことができます。

Animated.timing(...).start(({finished}) => {
// 終了時に呼ばれる
})

Animation できるコンポーネント

  • View, Text, Image, ScrollView, FlatList, SectionList がデフォルトで対応しています。
  • Animated.createAnimatedComponent で自作できるらしいです。