😸

【Flutter Widget of the Week #17】Heroを使ってみた

2022/10/22に公開

はじめに

Flutter Widget of the Week #17 Hero についてまとめましたので、紹介します。
https://youtu.be/Be9UH1kXFDw

Hero

Hero とは タップした画像が大きくなったり移動したりしながら画面遷移の動きをするアニメーションの一種です。
Hero トランジション
Hero トランジション
こうした動きを Hero トランジションと呼び、Flutter に限らず使われる一般的なUIパターンです。
Flutter では Hero widget を使うことで実現できます。
では、サンプルを動かして使い方を見てみましょう。

Hero サンプルコード

サンプルは PCの写真をタップするとタップした画像が中央に移動する動きになってます。
Hero サンプル実行画面
Hero サンプル実行画面

main.dart
// 画面遷移前
class MainScreen extends StatelessWidget {
  const MainScreen({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Main Screen'),
      ),
      body: GestureDetector(
        onTap: () {
          Navigator.push(context, MaterialPageRoute(builder: (context) {
            return const DetailScreen();
          }));
        },
        child: Hero( // 画面遷移前の Hero 
          tag: 'imageHero', // 画面遷移後の tag と共通 
          child: Image.network(
            'https://picsum.photos/250?image=9',
          ),
        ),
      ),
    );
  }
}

// 画面遷移後
class DetailScreen extends StatelessWidget {
  const DetailScreen({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: Center(
          child: Hero( // 画面遷移後の Hero 
            tag: 'imageHero', // 画面遷移前の tag と共通
            child: Image.network(
              'https://picsum.photos/250?image=9',
            ),
          ),
        ),
      ),
    );
  }
}

使い方としては、
まず画面遷移前と画面遷移後の Widget を Hero で囲みます。
次に Hero の tag プロパティに2つの画面で共通のタグ名を指定します。
以上により、画面遷移前から画面遷移後の画面に遷移するときに Hero トランジションが実行されるようになります。

上記のサンプルコードを例に見てみましょう。
画面遷移前が MainScreen、画面遷移後が DetailScreen として今回は画像にアニメーションをつけたいので、 画像を表示する widget である Image.network を Hero で囲みます。

child: Hero(
  tag: 'imageHero',
  child: Image.network(
    'https://picsum.photos/250?image=9',
  ),
),

そして、Hero widget が入ってる2つの画面がつながっていることを示すために、
両方の tag プロパティに 'imageHero'を指定します。
これだけで Hero トランジションが実現できました。

また、ClipRRect 等の clip を使うことで一味違ったアニメーションを実現することもできりと、いろいろ試してみると面白いです。
ClipRRect 等の clip を使うことで一味違ったアニメーションも実現できる
ClipRRect 等の clip を使うことで一味違ったアニメーションも実現できる

Hero のプロパティについて

Hero にはプロパティがいくつかあります。
とはいえ基本的には tag だけしか使わないと思いますので、ほんの一部だけ紹介します。

(new) Hero Hero({
  Key? key,
  required Object tag,
  Tween<Rect?> Function(Rect?, Rect?)? createRectTween,
  Widget Function(BuildContext, Animation<double>, HeroFlightDirection, BuildContext, BuildContext)? flightShuttleBuilder,
  Widget Function(BuildContext, Size, Widget)? placeholderBuilder,
  bool transitionOnUserGestures = false,
  required Widget child,
})

①tag

tagを使って、対象の widget が両方の画面のどこにあるのかを把握するために指定する
これは一つの画面に Hero を2つ以上使ったときにどちらがどの画面の widget とつながっているのかを分かるようにするために必須の値です。
型は Object 型

②transitionOnUserGestures

バックスワイプしたときに Hero トランジションを実行するかどうかを指定する
transitionOnUserGestures は2つの画面に入れた Hero 両方を変更しないと適応されないので注意してください。
デフォルトは false
型は bool 型
1.false の場合
transitionOnUserGestures が false の場合
2. true の場合
transitionOnUserGestures が true の場合

最後に

今回は Hero を紹介しました。画像をタップしたらその画像が前に飛び出すように動きはアプリを使っていたら良くみるアニメーションだと思います。それがこんな簡単にできるとは驚きです。アプリ開発をするときにも使いたい widget ですね。
次は #18 CustomPaint です。またお会いしましょう。

参考記事

https://docs.flutter.dev/cookbook/navigation/hero-animations
https://docs.flutter.dev/development/ui/animations/hero-animations

Discussion