React Native でインタラクティブなカードを作る

// 🙎‍♂️ Yuji Tsuburaya📆 December 12, 2018🔖 React Native

以前の記事 ではLayoutAnimation を使ったアニメーションの実現方法を紹介しました。今回は Animated を使ったアニメーションのパターンを紹介したいと思います。

Animated で何ができるのか?

要素自体の変形、回転、移動をさせることができます。始点( Animated.Value(0))と終点(toValue)の値を Animated でオブジェクトで定義し、その間を補間することでアニメーションを実現します。

アニメーションさせることができるのは、画像(Animated.Image )、スクロールビュー、(Animated.ScrollView)、テキスト(Animated.Text)、ビュー(Animated.View)の4つになります。今回の記事では以下のような、タップしたときに変形するカードをAnimated.Viewと Animated の API を使って実現していきたいと思います。

カードは以下のような流れで作成していきます。

  1. カードのサイズのデータを state で定義する
  2. カードのタップ ( onPressIn/onPressOut)を検知し、アニメーションを発火させる

カードのサイズの情報を初期化した State を準備する

this.state = { sizeRatio: new Animated.Value(1), };

state にカードのサイズのデータを宣言しておきます。 new Animated.Value(1) はアニメーション用オブジェクトの初期化方法です。引数には初期値を渡しますが、今回は、デフォルトのサイズを 1 (100%) と定義しました。アニメーションを発火させるタイミングで、このサイズを 0.94 (94%)に変更していきます。

Animatedオブジェクトにはさまざまな便利なメソッドが準備されているので、詳しくは公式ページahttps://reactnative.dev/docs/animated#docsNav参照すると良いと思います。

カードのタップ ( onPressIn / onPressOut )を検知し、アニメーションを発火させる

onPressIn で発火するサンプルコードです。 タップすることで、もともとの大きさ 1 が、 0.94 に変化します。ここでの変化は線形ではなく、 spring (ばね) の動きでアニメーションします。

Animated の値を変化させるには Animated.decay() Animated.spring() Animated.timing() などのメソッドを使用して、初期化した値を変化させます。変化の種類によって使用するメソッドが異なりますが、今回は、ばねのような動きを再現したかったので .spring() メソッドを使用しました。(だいたいのアニメーションはこのばねの動きで再現可能です)

Animated.spring(変化させたい値のstate, アニメーションプロパティオブジェクト)

.spring()メソッドの第一引数には変化させたい値のstate を渡します。今回でいうと、カードの大きさを保持する sizeRatioを渡しています。

また、第二引数にはアニメーションの設定オブジェクトを渡します。 toValueで、カードの大きさを 100% から 94% に変更するようにしています。 friction と tension はコード内のコメントにあるように摩擦とばね定数です。 friction が大きいほどばねの振動の減衰が激しく、 tension が大きいほどばねの強度が増し、振動数が大きくなります。

アニメーションさせるカードの実装

つづいてカードのビューを実装していきます。アニメーションを使用する場合には、通常の <View>ではなく、以下のように<Animated.View>を使用します。 Animated を付け忘れると、謎のエラーを吐くので注意が必要です。なかなか忘れがち。

<Animated.View style={[ styles.card, this.props.style, { transform: [{ scale: this.state.sizeRatio }], }, ]} > {this.props.children} </Animated.View>

通常のスタイルに加えて、カードの大きさを変更させるスタイルを追記します。今回アニメーションさせたいのは大きさなので、 transform / scaleを使用します。

こちらも詳しくは 公式ドキュメント を参照いただければと思いますが、大きさだけでなく、要素の移動や要素の回転角などをアニメーションさせることももちろん可能です。

(メモ) 今回使用してないアニメーション周りの技術

要素をアニメーションによって指定の位置まで移動させたい場合translateX や translateY を使用します。

色をアニメーションによって動的に変化させたい場合色コードなどは、 Animated オブジェクトで値を初期化することができません。そのような場合には interpolate() を使用します。アニメーションの state が 0 から 1 に変化したときに、色コードを指定してやることで、0 から 1 の変化に対応する色コードを変化させることができます。以下の例だと白から黒に動的に変化します。

value.interpolate({ inputRange: [0, 1], outputRange: ['#FFFFFF', '#000000'], });

角度とかを変化させたい場合にも interpolate() が使用できます。

まとめ

以上の手順を踏むと、タップしたときに伸縮するカードを作成することができます。

LayoutAnimation より記述量こそ多いものの、Animated を使用することで、より柔軟なアニメーションが可能になります。作成したカードコンポーネントと呼び出しコードはこちらの Gist に掲載してあるのでぜひご参照ください。コピペすればそのまま動くはず。

次は PanResponder あたりの記事を書きたい気持ち。質問等あれば @___35d までリプライまたはDMください。

以前の記事 ではLayoutAnimation を使ったアニメーションの実現方法を紹介しました。今回は Animated を使ったアニメーションのパターンを紹介したいと思います。

以前の記事 ではLayoutAnimation を使ったアニメーションの実現方法を紹介しました。今回は Animated を使ったアニメーションのパターンを紹介したいと思います。

シェアしてくれたら喜びます 👨‍🎤

広告

書いた人

___35d

Yuji Tsuburaya (@___35d

👩‍💻 Frontend Engineer

🏢 J-CAT CTO Co-Founder / ex. BizReach

🎨 by @ch1ch1ch1_123

💚 Minimalism / Notion / Figma

📱 Author of @FastNotion

詳しいプロフィールはこちら

広告