デバイスと環境
useAnimatedKeyboard・useAnimatedSensorでデバイス由来の値をアニメーションに使い、useReducedMotionとReducedMotionConfigでアクセシビリティ設定に対応します。
ジェスチャーやスクロールは、ユーザーが画面に触れて生まれる値でした。この章で扱うのは、それとは別の入力源です。仮想キーボードの高さ、端末のセンサーが返す傾きや加速度、そしてユーザーのアクセシビリティ設定。これらもまた、共有値を経由してアニメーションに流し込めます。
これらの機能の多くは実機のハードウェアやOS設定に依存するため、ブラウザでそのまま再現するのは難しい面があります。この章ではコード例を中心に据えつつ、ブラウザで確かめられるものは動くデモも用意します。
キーボードの高さに合わせる
useAnimatedKeyboardは、仮想キーボードの状態と高さをもとにアニメーションを組み立てるためのフックです。キーボードがせり上がってくる分だけ、入力欄を押し上げるといった動きに使います。
import { useAnimatedKeyboard, useAnimatedStyle } from "react-native-reanimated";
function App() {
const keyboard = useAnimatedKeyboard();
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ translateY: -keyboard.height.value }],
}));
}
戻り値は2つの共有値を持つオブジェクトです。heightは現在のキーボードの高さ、stateはキーボードの状態で、OPENING・OPEN・CLOSING・CLOSED(および初期状態のUNKNOWN)のいずれかを表すKeyboardStateが入ります。引数にはisStatusBarTranslucentAndroidを持つオプションオブジェクトを渡せます(既定はfalse、iOSでは無視されます)。
Androidでは、いくつか前提があります。AndroidManifest.xmlのandroid:windowSoftInputModeをadjustResizeに設定しておく必要があり、このフックを使うとアプリ全体でAndroid標準のリサイズ挙動が無効になります。
キーボードはブラウザでの再現が難しいため、ここではコード例の紹介にとどめます。動作の確認は実機で行ってください。
センサーの値を使う
useAnimatedSensorは、端末のセンサーから得たデータをもとにアニメーションを作ります。加速度計、ジャイロスコープ、重力、磁界、回転の5種類にアクセスできます。
import { useAnimatedSensor, SensorType } from "react-native-reanimated";
function App() {
const gravity = useAnimatedSensor(SensorType.GRAVITY);
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: withSpring(gravity.sensor.value.x * 20) },
{ translateY: withSpring(gravity.sensor.value.y * 20) },
],
}));
}
第1引数sensorTypeには、SensorType列挙型で使いたいセンサーを指定します。ACCELEROMETER(重力を除いた加速度)、GYROSCOPE(回転の速さ)、GRAVITY(重力ベクトル)、MAGNETIC_FIELD(磁界)、ROTATION(3次元の姿勢)が選べます。
第2引数configは省略可能で、interval(読み取り間隔のミリ秒。既定の"auto"は画面リフレッシュレートに合わせます)、adjustToInterfaceOrientation(画面の向きに合わせて補正するか)、iosReferenceFrame(iOSでの基準座標系)を持ちます。
戻り値は、センサーの測定値を持つ共有値sensorのほか、購読を止めるunregister、センサーが使えるかを示すisAvailable、設定内容のconfigを持つオブジェクトです。GRAVITYのようなセンサーはx・y・zの3軸の値を返し、ROTATIONはオイラー角(roll・pitch・yaw)とクォータニオンを返します。
次のデモは、実センサーの代わりにスライダーで重力ベクトルのx・yを動かし、その値をwithSpringでボックスの移動に変換したものです。実機では、この2つのスライダーがセンサーの測定値に置き換わると考えてください。
アクセシビリティ設定に対応する
OSには「視差効果を減らす」「アニメーションを減らす」といったアクセシビリティ設定があります。動きに敏感なユーザーのために、アプリ側でもこの設定を尊重したいところです。
useReducedMotionは、この「動きを減らす」設定を照会するフックです。アプリ起動時にこの設定が有効だったかどうかを、真偽値で同期的に返します。
import { useReducedMotion } from "react-native-reanimated";
function App() {
const reduceMotion = useReducedMotion();
if (reduceMotion) {
// 静的な表示にする
} else {
// アニメーションを実行する
}
}
次のデモは、useReducedMotionの値を見て、動きを減らす設定が無効なら往復アニメーションを実行し、有効ならボックスを止めます。OSやブラウザで「動きを減らす」を有効にして読み込み直すと、表示が切り替わります。
useReducedMotionについて、2点だけ補足します。設定を後から変えてもコンポーネントは再レンダリングされません(値はあくまで起動時のものです)。また、AccessibilityInfo.isReduceMotionEnabled()が非同期なのに対し、このフックは値を同期的に取得できます。
設定への対応をアプリ全体でまとめて行いたいときは、ReducedMotionConfigコンポーネントを使います。既定では、動きを減らす設定が有効なときにすべてのアニメーションを無効化します。その振る舞いをmodeで調整できます。
import { ReducedMotionConfig, ReduceMotion } from "react-native-reanimated";
function App() {
return (
// ...
<ReducedMotionConfig mode={ReduceMotion.Never} />
// ...
);
}
modeにはReduceMotion列挙型の3つの値を渡せます。Systemはデバイスの設定に従い(有効ならアニメーションを無効化)、Alwaysは設定に関わらず常に無効化、Neverは常に有効のままにします。
この章のまとめ
useAnimatedKeyboardはキーボードの高さと状態を共有値で返します。ただしReanimated 4.xで非推奨となり、公式はreact-native-keyboard-controllerへの移行を勧めていますuseAnimatedSensorは加速度計や重力などのセンサー値を共有値で返します。使えるかどうかはisAvailableで確認できますuseReducedMotionは「動きを減らす」設定を同期的に取得します。ReducedMotionConfigを使うと、対応をアプリ全体でまとめて指定できます
これで第3部は終わりです。ジェスチャー・スクロール・デバイスと、ユーザーや環境から生まれる値を共有値へ流し込み、アニメーションへ変換する流れをひととおり見てきました。次の第4部では、要素の出現や消滅、レイアウトの変化そのものをアニメーションさせるレイアウトアニメーションを扱います。