FlutterでReduxアーキテクチャパターンを採用している場合、StatelessWidgetでの構築がメインになると思います。
ウィジェットをアニメーションさせたい場合が必ず出てくると思いますが、アニメーションは基本的にStatefulWidgetで行う事が前提となっているようで私は悩みました。
公式のドキュメントをみてみると、Statelessでアニメーションをさせる例がありますが、パラメータとしてStatefulWidgetで作成したAnimationControllerを持っている為、StatefulWidgetから呼び出す前提の方法になります。
この記事では、完全StatelessWidgetだけでウィジェットにアニメーションを持たせる方法を紹介したいと思います。
FlutterのReduxについてはこちらの記事でまとめています。
ここから先の解説はこの記事に沿ってReduxを導入した前提で進めていきますので一度ご覧ください。
アニメーションを持たせる手順
今回紹介する方法はこちらの記事を参考にしました。圧倒的感謝!
How to create animations in Flutter with Redux?
①アニメーションを表示させるStatelessWidgetとアニメーションさせるWidget部品を作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
import 'package:flutter/material.dart'; /// アニメーションを使用するStatelessWidgetなクラス class TestWidget extends StatelessWidget { /// Reduxストア final Store<RootState> store; /// ツールバーの高さ final double _toolbarHeight = 80.0; TestWidget({this.store}); @override Widget build(BuildContext context) { return Stack( children: <Widget>[ Container( child: GestureDetector( child: _viewWidget.createWidget(), onTap: () { debugPrint('タップ検知'); store.dispatch(ChangeToolBar()); // ツールバー表示ステート切り替え } ), ), // ツールバーステートが切り替わると再構成される // 今回のツールバー状態はbool型変数で管理している StoreConnector<RootState, bool>( distinct: true, converter: (store) => store.state.testWidgetState?.toolbarflg, builder: (context, flg) { // ツールバー作成関数呼び出し return _toolBarWidget(flg, context); } ), ], ), ); } /// ツールバー作成処理 /// 引数:表示フラグ、BuildContext Widget _toolBarWidget( bool openflg, BuildContext context, ) { if(openflg) { // ツールバー表示 return Align( alignment: Alignment.bottomCenter, child: Container( height: _toolbarHeight, child: Row( children: <Widget>[ // ツールバー閉じる Expanded( child: FlatButton( child: Icon(Icons.close, color: Colors.blue,), onPressed: () { store.dispatch(ChangeToolBar()); }, ), ), // 戻る Expanded( child: FlatButton( child: Icon(Icons.arrow_back_ios, color: Colors.blue,), onPressed: () { debugPrint("戻る"); }, ), ), // 次へ Expanded( child: FlatButton( child: Icon(Icons.arrow_forward_ios, color: Colors.blue,), onPressed: () { debugPrint('次へ'); }, ), ), // リロード Expanded( child: FlatButton( child: Icon(Icons.refresh, color: Colors.blue,), onPressed: () { debugPrint('リロード'); }, ), ), // ホームに戻る Expanded( child: FlatButton( child: Icon(Icons.home, color: Colors.blue,), onPressed: () { debugPrint('ホームに戻る'); }, ), ), ], ), ), ); } else { // ツールバー非表示(ダミーでContainerを返す) return Container(); } } } |
今回は例として画面にツールバーを表示・非表示させるウィジェットを作ります。
画面をタップすると画面下にツールバーが表示します。
もう一度画面をタップするとツールバーが閉じます。
ReduxのStoreConnectorによってStatelessWidgetでも動的に状態を変更させる事ができますが、これだけだとまだアニメーションが設定されていないので、パッパッと瞬時にツールバーが出し入れされてしまいます。
②Widget部品にアニメーションを追加する
アニメーションさせる手段として「AnimationContainer」を利用します。
AnimationContainerについては以下の動画と記事が参考になります。
https://flutter.ctrnost.com/basic/animation/animatedcontainer/
先ほどのソースのツールバー作成処理に変更を加えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
/// ツールバー作成処理 /// 引数:表示フラグ、BuildContext Widget _toolBarWidget( bool openflg, BuildContext context ) { return Align( alignment: Alignment.bottomCenter, child: AnimatedContainer( // アニメーション設定 height: _toolbarHeight, duration: Duration(milliseconds: 200), transform: Matrix4.translationValues( 0, openflg ? 0 : _toolbarHeight, 0 ), color: Colors.white.withOpacity(0.7), child: Row( // childにツールバーの中身を構築する children: <Widget>[ Expanded( child: FlatButton( child: Icon(Icons.close, color: Colors.blue,), onPressed: () { store.dispatch(ChangeToolBar()); }, ), ), // 戻る Expanded( child: FlatButton( child: Icon(Icons.arrow_back_ios, color: Colors.blue,), onPressed: () { debugPrint("戻る"); }, ), ), // 次へ Expanded( child: FlatButton( child: Icon(Icons.arrow_forward_ios, color: Colors.blue,), onPressed: () { debugPrint("次へ"); }, ), ), // リロード Expanded( child: FlatButton( child: Icon(Icons.refresh, color: Colors.blue,), onPressed: () { debugPrint("リロード"); }, ), ), // ホームに戻る Expanded( child: FlatButton( child: Icon(Icons.home, color: Colors.blue,), onPressed: () { debugPrint("ホームに戻る"); }, ), ), ], ), ), ); } |
表示フラグがFalseの場合ツールバーの高さを0にし、Trueの場合に本来の高さを持たせるようにしています。
高さが切り替わる瞬間にスライドイン・アウトアニメーション(でいいのかな?)を付与しています。
StatelessWidgetだけでもアニメーション付けられるんですね!
けっこう焦りました笑