こんにちは。スマホアプリをメインに開発しているロッキーカナイです。
記事が大分ご無沙汰になってしまいましたが、今回はFlutterでカスタムダイアログの実装について紹介したい思います。
まずFlutterでダイアログを実装する場合は、SimpleDialogやAlertDialogを使うと思うのですが、クライアントの要望にあったオシャンティなダイアログを作るとなると、これらでは実現出来ません。そこでカスタムダイアログを用いて実装します。
ではカスタムダイアログの実装を見てみましょう。
実装説明
ModalRouteを継承したページを用意し、モーダル画面遷移させて現在のページの上にかさねる感じになります。
よって、現在のページ上にボタンがあったとしてもタッチは届かず、ダイアログとしての機能を満たします。
ModalRouteを継承したルートクラスを実装
ModalRouteを継承したModalOverlayクラスを追加します。
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 |
import 'package:flutter/material.dart'; /* * モーダルオーバーレイ */ class ModalOverlay extends ModalRoute<void> { // ダイアログ内のWidget final Widget contents; // Androidのバックボタンを有効にするか final bool isAndroidBackEnable; ModalOverlay(this.contents, {this.isAndroidBackEnable = true}) : super(); @override Duration get transitionDuration => Duration(milliseconds: 100); @override bool get opaque => false; @override bool get barrierDismissible => false; @override Color get barrierColor => Colors.black.withOpacity(0.5); @override String get barrierLabel => null; @override bool get maintainState => true; @override Widget buildPage( BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, ) { return Material( type: MaterialType.transparency, child: SafeArea( child: _buildOverlayContent(context), ), ); } @override Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { return FadeTransition( opacity: animation, child: ScaleTransition( scale: animation, child: child, ), ); } Widget _buildOverlayContent(BuildContext context) { return Center( child: dialogContent(context), ); } Widget dialogContent(BuildContext context) { return WillPopScope( child: this.contents, onWillPop: () { return Future(() => isAndroidBackEnable); }, ); } } |
Androidで実機のバックボタンを押すとダイアログが閉じてしまうので、有効無効の切り替えができるようにしました。dialogContentメソッドのWillPopScopeクラスのonWillPopでポップする際にコールバックが呼ばれて、bool値を返すことで切り替えしてます。
また、ModalOverlayではcontentsというWidgetをもらってそれを表示させるようにしました。
ダイアログのコンテンツクラスを実装
CustomDialogというクラスを作り、ここでModalOverlayのコンテンツを作って渡すのと、push遷移させます。
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 110 111 112 113 |
import 'package:flutter/material.dart'; import 'package:test_project/ModalOverlay.dart'; class CustomDialog { BuildContext context; CustomDialog(this.context) : super(); /* * 表示 */ void showCustomDialog() { Navigator.push( context, ModalOverlay( Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Stack( children: <Widget>[ Image.asset( "images/fukidashi.png", fit: BoxFit.fitWidth, ), Container( height: 200.0, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ /* * タイトル */ Text( "カスタムダイアログ", style: TextStyle( fontSize: 30.0, fontWeight: FontWeight.bold, locale: Locale("ja", "JP"), ), ), /* * メッセージ */ Text( "こんな感じでダイアログが出せるよ", style: TextStyle( fontSize: 16.0, locale: Locale("ja", "JP"), ), ), ], ), ) ) ], ), /* * OKボタン */ Row( children: <Widget>[ Expanded( child: Container(), ), FlatButton( color: Colors.blue, child: Text( "OK", style: TextStyle( color: Colors.white, fontSize: 18.0, fontWeight: FontWeight.bold, locale: Locale("ja", "JP"), ), ), onPressed: () { hideCustomDialog(); }, ), SizedBox( width: 80.0, ) ], ), ], ) ), isAndroidBackEnable: false, ), ); } /* * 非表示 */ void hideCustomDialog() { Navigator.of(context).pop(); } } |
呼び出しは以下のようにします。
1 2 3 4 5 6 |
onPressed: () { CustomDialog( context, ).showCustomDialog(); }, |

フキダシはここのを使用しました。
まとめ
いかがでしたでしょうか?
ModalRouteを使ってカスタムダイアログの実装を紹介をしました。
今回作ったModalOverlayを用いて、通信中などで使うインジケータビューとしても使うことができますので、次回はその紹介をしたいと思います。
いつかマイブームのキックボクシングの記事書けたらいいなぁ。
