【Flutter】HeroWidgetでリッチな画面遷移を実装する



HeroWidgetを使用して簡単にリッチな画面遷移を実装していきます。

## 動作

　<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466417/26ddfed8-94dd-e88c-70ae-0c95cc4418f0.gif' width='250'>

## これだけ
HeroWidgetは指定した2つのWidget間で自動的にトランジションを作成してくれるので、Heroで囲った2つのWidgetを用意。

```dart
class MyHomePage extends StatelessWidget {
// ↓一つ目
         GestureDetector(
        onTap: () {
          Navigator.of(context).push(
            MaterialPageRoute(
              fullscreenDialog: true,
              builder: (BuildContext context) => DetailPage(),
            ),
          );
        },
        child: Card(
          margin: const EdgeInsets.all(24),
          elevation: 4.0,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(12.0),
          ),
          clipBehavior: Clip.antiAlias,
          child: Hero(
            tag: 'uniqueTag',
            child: Image.network(
              'https://images.unsplash.com/photo-1595581831735-ec7a54193665?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1729&q=80',
              fit: BoxFit.cover,
              // height: 100,
            ),
          ),
        ),
      ),
}

class DetailPage extends StatelessWidget {
// 二つ目
                Hero(
                  tag: 'uniqueTag',
                  child: GestureDetector(
                    onTap: () => Navigator.pop(context),
                    child: Image.network(
                      'https://images.unsplash.com/photo-1595581831735-ec7a54193665?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1729&q=80',
                      fit: BoxFit.cover,
                    ),
                  ),
                ),

}

```
HeroWidgetの`tag`プロパティには同一のtag名を指定してください。あとは画面遷移を実装するだけで動画のようにリッチな画面遷移が実装できます。

## 活用例
ユーザープロフィールを表示させる時とかに使えそうです。`tag`プロパティにはインデックスを指定しています。
　<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466417/6d2a62aa-b3a2-623e-880a-0f7a4d7b2b19.gif' width='250'>

## 全体コード
コピペで動きます。

```dart

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Hero Sample'),
      ),
      body: GestureDetector(
        onTap: () {
          Navigator.of(context).push(
            MaterialPageRoute(
              fullscreenDialog: true,
              builder: (BuildContext context) => DetailPage(),
            ),
          );
        },
        child: Card(
          margin: const EdgeInsets.all(24),
          elevation: 4.0,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(12.0),
          ),
          clipBehavior: Clip.antiAlias,
          child: Hero(
            tag: 'uniqueTag',
            child: Image.network(
              'https://images.unsplash.com/photo-1595581831735-ec7a54193665?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1729&q=80',
              fit: BoxFit.cover,
              // height: 100,
            ),
          ),
        ),
      ),
    );
  }
}

class DetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          Center(
            child: Column(
              children: <Widget>[
                Hero(
                  tag: 'uniqueTag',
                  child: GestureDetector(
                    onTap: () => Navigator.pop(context),
                    child: Image.network(
                      'https://images.unsplash.com/photo-1595581831735-ec7a54193665?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1729&q=80',
                      fit: BoxFit.cover,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

```

手軽におしゃれな画面遷移を実装することができるので皆さんも実装してみてはいかがでしょうか。

## 参考
https://docs.flutter.dev/development/ui/animations/hero-animations

https://youtu.be/Be9UH1kXFDw