Agletというスニーカーを集めるアプリがありますが、そのアプリで新たにアイテムが手に入った時に流れるアニメーションのインパクトが強かったため、react-native-skiaで再現してみました。ロゴとテキストが斜め横に無限に移動し続けます。
テキストとロゴは適当なものに変えています。
実装順序としては
という流れです。
テキストを画面に並べて横まで埋まるようにします。事前にテキスト(+ロゴ)の横幅を計算しておきます。以下のように、横に並べる数を画面サイズに応じて計算します。斜めになっても途切れないように、少し画面幅よりも多めに計算します。
Math.floor((windowSize.width * 1.3) / Constants.messageGroupWidth) + 1
そして横移動が無限ループに見えるように、グループを横にもう一つ追加します。なぜもうひとつ横並びにするかについては、以下の記事を読むと仕組みがわかりやすいです。
写真が画面の端から端へ流れる無限ループするアニメーション | chocolat | Freelance Frontend Developer based in Tokyo, Japan.
左方向に移動する場合には右に追加のグループを配置し、右方向に移動する場合は左に追加のグループを配置するようにします。このように配置しておき、横に移動させた後また元の位置に戻り移動を繰り返すと無限ループしているように見えます。
こうして作成した行を一定の間隔で縦に並べ画面を埋めます。
react-native-skiaの場合、以下でアニメーションをループさせることができます。
const progress = useTiming(
{ loop: true, yoyo: false },
{ duration: 5000 }),
progressの値は0.0から1.0まで変化するのを繰り返します。
オプションのyoyo
はfalseにします。trueにすると一度進みきったところから戻るアニメーションが発生してしまうためです。なぜyoyo
というのかわかりませんが、これは日本語のヨーヨーを指しているのかもしれません(一度進んだら戻ってくる)。
このprogress
の値を元にしてグループに対して横移動をかけます。値が0のときは移動せず、値が1のときは画面幅の分、横に移動します。左に移動する場合はマイナスします。
const transform = useComputedValue(() => {
const distance = props.progress.current * groupWidth
return [
{
translateX: distance * (props.direction === "left" ? -1 : 1),
},
]
}, [props.progress, props.direction])
return (
<Group transform={transform}>
...
</Group>
)
角度を斜めにするには、全体をグループで覆ってtransformをかければOKです。
<Group transform={[{ rotate: Math.PI / 12 }]} origin={{ x: 0, y: 0 }}>
...
</Group>
これで完成です。
実際のコードは以下で確認できます。