2021/3/18 : Flutter : animationsパッケージのOpenContainerウィジェットを使ってみる。

 

null safety article

https://pub.dev/packages/animations/example

pub.devのanimationsパッケージのページにサンプルコード(へのリンク)がありますが、少し複雑なので、もう少し簡単なもので使ってみて、利用方法を整理したいと思います。


スタート地点。

https://pub.dev/packages/animations/install

↑の通りanimationsパッケージの依存関係をpubspec.yamlで宣言しましょう。

//main.dart
import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
//↑animationsパッケージが必要なのでインポートする。
void main() {
  runApp(
    MaterialApp(
      home: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          ElevatedButton(
            child: Text("next"),
            onPressed: () {},
          ),
        ],
      ),
      body: Center(
        child: GestureDetector(
          onTap: () {
            print("Containerをタップ");
            Navigator.of(context).push(MaterialPageRoute(
              builder: (context)=>NextPage(),
            ));
          },
          child: Container(
            height: 200.0,
            color: Colors.indigoAccent,
          ),
        ),
      ),
    );
  }
}

class NextPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:AppBar(),
      body: Container(
        color: Colors.pink[200],
      ),
    );
  }
}

青いContainerをタップするとピンク色のNextPageに遷移するだけです。

ページ遷移方法を、OpenContainerを使ってアニメーション化します。


(1)GestureDetectorの部分をOpenContainerでラップします。

GestureDetectorの部分にカーソルを合わせてoption+enterキーを押し、「Wrap with widget」を選択します。

プロパティはchildではなく、closedBuilderにします。

closedBuilderプロパティには引数を二つ取るコールバックを設定します。

このコールバックは閉じた状態のウィジェットを返すようにします。

今回閉じた状態の時のウィジェットは「青いContainer」なので以下のようになります。

コールバックの第二引数のopenCotnainerを呼び出すとオープンする、という仕組みなので、下記のようにonTapプロパティのコールバックの中でopenContainerコールバックを呼び出します。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          ElevatedButton(
            child: Text("next"),
            onPressed: () {},
          ),
        ],
      ),
      body: Center(
        child: OpenContainer(
          closedBuilder: (context,openContainer)=>GestureDetector(
            onTap: () {
              print("Containerをタップ");
              openContainer(); 
            },
            child: Container(
              height: 200.0,
              color: Colors.indigoAccent,
            ),
          ),
        ),
      ),
    );
  }
}

 




(2)openBuilderプロパティに遷移先ウィジェットを返すコールバックを設定する。

今回の遷移先ウィジェットはNextPageなので以下のように設定します。

child: OpenContainer(
  openBuilder:(context,_)=>NextPage(),//←ココ
  closedBuilder: (context,openContainer)=>GestureDetector(
    onTap: () {
      print("Containerをタップ");
      openContainer();
    },
    child: Container(
      height: 200.0,
      color: Colors.indigoAccent,
    ),
  ),
),

 




(3)一応必須の引数はこれだけなので動かしてみます。

紙芝居ではアニメーションをお見せできませんが、ページ遷移をアニメーション化できていますね。

特にAnimationControllerなどを用意することもないので、これは便利と言えるのではないでしょうか。

とりあえずこの時点での全コード↓

import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
//↑animationsパッケージが必要なのでインポートする。
void main() {
  runApp(
    MaterialApp(
      home: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          ElevatedButton(
            child: Text("next"),
            onPressed: () {},
          ),
        ],
      ),
      body: Center(
        child: OpenContainer(
          openBuilder:(context,_)=>NextPage(),
          closedBuilder: (context,openContainer)=>GestureDetector(
            onTap: () {
              print("Containerをタップ");
              openContainer();
              //↑ここでopenContainerを呼び出すことで、青いコンテナをタップしたら
              //NextPageにアニメーション化で遷移する。
            },
            child: Container(
              height: 200.0,
              color: Colors.indigoAccent,
            ),
          ),
        ),
      ),
    );
  }
}

class NextPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:AppBar(),
      body: Container(
        color: Colors.pink[200],
      ),
    );
  }
}

 




(4)最低限のプロパティは上記の通りなんですが、他のプロパティも設定してみましょう。

closedElevationプロパティで閉じている状態のウィジェットにエレベーションをつけられます。

OpenContainer(
          closedElevation: 5.0,

 

わかりにくいですが、コンテナの下に影がつきました。


transitionDurationプロパティでページ遷移アニメーションの時間を指定できます。

OpenContainer(
          transitionDuration: Duration(seconds:2),

これで2秒かけてページ遷移アニメーションが進行します。


onClosedプロパティのコールバックはコンテナが閉じる時に呼び出され、その際遷移先から引数を受け取ることができる模様。

まずその引数の型をOpenContainerの型引数として宣言するんですね。

例えば、遷移先からString型のデータを受け取る場合

OpenContainer<String>(
   ...
   ...

↑のように宣言する。onClosedの型が下記のようなので、

void Function(String) onClosed

引数として遷移先から受け取った文字列を受け取り、それを使ってやりたいことを記述する、と。

import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
void main() {
  runApp(
    MaterialApp(
      home: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          ElevatedButton(
            child: Text("next"),
            onPressed: () {},
          ),
        ],
      ),
      body: Center(
        child: OpenContainer<String>(
          onClosed: (str)=>print("$strを受け取りました。"),
          transitionDuration: Duration(seconds:2),
          closedElevation: 5.0,
          openBuilder:(context,_)=>NextPage(),
          closedBuilder: (context,openContainer)=>GestureDetector(
            onTap: () {
              print("Containerをタップ");
              openContainer();
            },
            child: Container(
              height: 200.0,
              color: Colors.indigoAccent,
            ),
          ),
        ),
      ),
    );
  }
}

class NextPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:AppBar(),
      body: Container(
        color: Colors.pink[200],
        //↓遷移元に文字列を渡して遷移元に戻るボタンを設置。
        child:TextButton(
          child:Text("テキスト1",),
          onPressed:()=>Navigator.pop(context,"テキスト1"),
        ),
      ),
    );
  }
}

上記のサンプルは遷移先に設置した「テキスト1」ボタンを押して戻る時に、遷移先から文字列”テキスト1″を受け取り、コンソールに表示するサンプルです。

設置したボタンで戻るとコンソールに

flutter: テキスト1を受け取りました。

のように表示されました。

例の如くシステムバックボタン(appBarの左上に自動的に表示される戻るボタン)で戻った場合

flutter: nullを受け取りました。

となりました。

あとは遷移アニメーションの色や形を指定するプロパティもあるようなのでお好みで使いましょう。

以上です。

 

コメントを残す

メールアドレスが公開されることはありません。