Ionicアニメーションで遊ぼう


はじめに

こんにちは!

最近はかっこいいアニメーションをするUIが多いですね。
UI/UXを考える上で、アニメーションは必須技術となっています。
そこで、今回はIonicアニメーションで遊んでみたいと思います。

元ネタは次のページです。詳しく学びたい方は次のリンクからどうぞ!


自己紹介

  • Twitter: s_kozake
  • 特技: 🍺が好きです

ジェスチャー

Ionicアニメーションで遊ぶ前に、ジェスチャーについて少し触れます。
アニメーションの動作させるには、ユーザーからの何らかの操作が起点となることが多いですので。
特にスマフォでは、スワイプやダブルタップ、ロングタップなど様々な操作があります。

このような複雑な操作をサポートするために、Ionicにはジェスチャーユーティリティが用意されています。
便利な世の中ですね!


ジェスチャーユーティリティのインストール

CDNからインストールすれば簡単です。
AngularとかReactなどのフレームワークがなくても使えるのは便利ですね!
もちろん、AngularやReact、Vueから使える手段も用意されています(むしろこちらが主流)。

import { createGesture } from 'https://cdn.jsdelivr.net/npm/@ionic/core@latest/dist/esm/index.mjs';

ジェスチャーの基本

createGesture 関数を使ってジェスチャーを作成します。
createGesture 関数の代表的なオプションは次のとおりです。

const gesture = createGesture({
  el: elementRef,              // ジェスチャーを受け取る対象要素
  disableScroll: false,        // ジェスチャーの間スクロールを無効にするかどうか
  direction: 'x',              // ジェスチャー検出を特定する軸
  gesturePriority: 0,          // ジェスチャーの優先度。高いものが優先される
  threshold: 15,               // ジェスチャー開始を判断する開始点からのポインタ移動量
  gestureName: 'my-gesture',   // ジェスチャーの名前
  onMove: ev => onMove(ev)     // ジェスチャー動作時に呼ばれるコールバック関数
});

ジェスチャーの基本

onMove に設定したコールバック関数に渡されるイベントでジェスチャー情報を取得できます。

const onMove = (detail) => {
  const type = detail.type;            // 検出されたジェスチャーのタイプ
  const startX = detail.startX;        // ジェスチャーを開始したx座標
  const currentX = detail.currentX;    // ジェスチャーの現在のx座標
  const deltaX = detail.deltaX;        // ジェスチャー開始点からのx軸上の移動距離
  const velocityX = detail.velocityX;  // ジェスチャーのx軸上の移動速度
}


ジェスチャーのデモ

See the Pen Ionic Gestures - Basic by Sinichi Kozake (@kozake) on CodePen.


アニメーション

では、Ionicアニメーションで遊んでいきましょう!
Ionicにはアニメーションを簡単に扱えるユーティリティが用意されています。
これを用いることで直感的にアニメーションを作成することができます。


アニメーションユーティリティのインストール

CDNからインストールすれば簡単です。
ジェスチャー同様、AngularやReact、Vueから使える手段も用意されています。

import { createAnimation } from 'https://cdn.jsdelivr.net/npm/@ionic/core@latest/dist/esm/index.mjs';

アニメーション(基本1)

createAnimation 関数を使ってアニメーションを作成します。

createAnimation()
  .addElement(document.querySelector('.square'))  // アニメーション対象要素
  .duration(1500)                                 // アニメーション間隔
  .iterations(1)                                  // アニメーション回数
  .fromTo('opacity', '1', '0.2');                 // 開始と終了

上記コードでは、1.5秒の間隔で透過が変化するアニメーションを作成しています。


アニメーション(基本1)のデモ

See the Pen Ionic Animations - Basic by Sinichi Kozake (@kozake) on CodePen.


アニメーション(基本2)

もっと複雑なアニメーションも簡単に作成できます!

const animation = createAnimation()
   .addElement(document.querySelector('.square'))
   .duration(1500)
   .iterations(Infinity)
   .direction('alternate')
   .fromTo('transform',
           'translateX(0px) scale(0.5) rotate(0)',
           'translateX(100px) scale(1) rotate(45deg)')
  .fromTo('opacity', '1', '0.2');

上記コードでは、1.5秒の間隔で透過や大きさ、傾きやX軸が変化するアニメーションを作成しています。
iterations(Infinity)と指定することで、アニメーションは停止するまで何度も繰り返されます。


アニメーション(基本2)のデモ

See the Pen Ionic Animations - Basic2 by Sinichi Kozake (@kozake) on CodePen.


アニメーション(キーフレーム)

キーフレームを使うと、さらに詳細にアニメーション動作を指定することができます!

const animation = createAnimation()
   .addElement(document.querySelector('.square'))
   .duration(1000)
   .keyframes([
     { offset: 0, transform: 'translateX(0px) rotate(0)' },
     { offset: 0.3, transform: 'translateX(150px) rotate(15deg)' },
     { offset: 1, transform: 'translateX(100px) rotate(0)' }
   ]);

上記コードでは、開始0.3秒後に右に150px移動し、45度回転します。
その後、0.7秒かけて左に50px移動して傾きも元に戻ります。


アニメーション(キーフレーム)のデモ

See the Pen Ionic Animations - Keyframes by Sinichi Kozake (@kozake) on CodePen.


アニメーション(グループ)

アニメーションをグループ指定することも出来ます!

const squareA = createAnimation()
  .addElement(document.querySelector('.square-a'))
  .keyframes([...]);

const squareB = createAnimation()
  .addElement(document.querySelector('.square-b'))
  .keyframes([...]);

const squareC = createAnimation()
  .addElement(document.querySelector('.square-c'))
  .duration(5000)
  .keyframes([...]);

const parent = createAnimation()
  .duration(2000)
  .iterations(Infinity)
  .addAnimation([squareA, squareB, squareC]);

上記コードでは、それぞれのアニメーションをまとめて動作させます。
squareAsquareBではアニメーション間隔を指定していないので、parentに指定された2秒が適用されますが、squareCでは指定した5秒間隔でアニメーションが実行されます。


アニメーション(グループ)のデモ

See the Pen Ionic Animations - Group by Sinichi Kozake (@kozake) on CodePen.


アニメーション(チェーン)

アニメーションを連鎖(チェーン)することもできます!

const squareA = createAnimation()
  .addElement(document.querySelector('.square-a'))
  .fill('none').duration(1000).keyframes([...]);

const squareB = createAnimation()
  .addElement(document.querySelector('.square-b'))
  .fill('none').duration(1000).keyframes([...]);

const squareC = createAnimation()
  .addElement(document.querySelector('.square-c'))
  .fill('none').duration(1000).keyframes([...]);

await squareA.play();
await squareB.play();
await squareC.play();

await でアニメーションの完了を待つだけです。簡単ですね!


アニメーション(チェーン)のデモ

See the Pen Ionic Animations - Chaining by Sinichi Kozake (@kozake) on CodePen.


アニメーション(ジェスチャー)のデモ

ジェスチャーと組み合わせた例が次のとおりです。
アニメーション動作をジェスチャーなどの情報と組み合わせて動作させることが出来ます。
下記のコードでは、四角をドラックして動かすことが出来ます。また、スワイプして動作させることも出来ます。

let initialStep = 0;
let started = false;

const square = document.querySelector('.square');
const MAX_TRANSLATE = 400;

const animation = createAnimation()
  .addElement(square)
  .duration(1000)
  .fromTo('transform', 'translateX(0)', `translateX(${MAX_TRANSLATE}px)`);

const gesture = createGesture({
  el: square,
  threshold: 0,
  gestureName: 'square-drag',
  onMove: ev: onMove(ev),
  onEnd: ev: onEnd(ev)
})

gesture.enable(true);

const onMove = (ev): {
  if (!started) {
    animation.progressStart();
    started = true;
  }

  animation.progressStep(getStep(ev));
}

const onEnd = (ev): {
  if (!started) { return; }

  gesture.enable(false);

  const step = getStep(ev);
  const shouldComplete = (Math.abs(ev.velocityX) > 0.2) ?
    initialStep == 0 : step > 0.5;

  animation
    .progressEnd((shouldComplete) ? 1 : 0, step)
    .onFinish((): { gesture.enable(true); });

  initialStep = (shouldComplete) ? MAX_TRANSLATE : 0;
  started = false;
}

const clamp = (min, n, max): {
  return Math.max(min, Math.min(n, max));
};

const getStep = (ev): {
  const delta = initialStep + ev.deltaX;
  return clamp(0, delta / MAX_TRANSLATE, 1);
}

アニメーション(ジェスチャー)のデモ

See the Pen Ionic Animations - Gesture by Sinichi Kozake (@kozake) on CodePen.


アニメーション(スクロール)

最後によくあるスクロールと連動してアニメーションするやつです。
画面下から出てくる四角がスクロールと連動して大きくなります。

const animation = createAnimation()
   .addElement(document.querySelector('.square'))
   .duration(1) 
   .fromTo('opacity', '0', '1')
   .fromTo('transform', 'scale(0)', 'scale(1)');

const square = document.querySelector('.square');

let started = false;

window.onscroll = () => {
  const documentHeight = document.documentElement.clientHeight;
  const scrollTop = document.documentElement.scrollTop;
  const targetPosition = square.offsetTop;

  const step = Math.min((scrollTop + documentHeight - targetPosition) / 200, 1);

  if(step > 0 && step < 1){
    if (!started) {
      animation.progressStart();
      started = true;
    }
    animation.progressStep(step);
  } else {
    if (started) {
      animation.progressEnd(step == 1 ? 1 : 0, step)
      started = false;
    }
  }
}

アニメーション(スクロール)のデモ

See the Pen Ionic Animations - Scroll by Sinichi Kozake (@kozake) on CodePen.


おわり

Ionicアニメーション楽しいですね!
色々と試して遊んでみてください🍻(´∀`*v)