画面の上にポップアップ的なものを表示したい
画面の下に表示したいのなら、ボトムシートがあるのでそれでいいと思います。
BottomSheet class
https://api.flutter.dev/flutter/material/BottomSheet-class.html
そうではなく、この手のものを「上に出したい!」という時にどうしたらいいかという話です。
検索しても意外と見つからなかったので、作りました。
(Material Design 的に上に出すってどうなの?という話はあるかと思いますが)
[2019/06/11 追記]
Material Design に「Banner」というものがあるのを教えていただきました。
https://material.io/design/components/banners.htmlhtml
下の GIF やコードもそれに準拠するよう変更しました
↓こういう、上部に何かのメッセージを出して、Closeボタンを押したら消えるというヤツです。
考え方
だいぶ泥臭い作り方してます。
Scaffold の Body 部分を
Stack → メイン表示部分(今回は Center(RaisedButton) だけ) → POP部分 (Container) → IconButton(Close ボタン)
という形にして、
- POP部分を表示するかどうか決める変数 _isTapClose を作る(初期値 false)
- POP部分は _isTapClose が false なら IconButton を含む内容、true なら Container() (空の Container)とする
- IconButton を押されたら _isTapClose を true にし、setState して StatefulWidget を再描画させる
- (必要に応じて)メイン表示部分はPOPの height 分だけ上方向に Margin を持たせる。_isTapClose が true になったら Margin の値を 0 にする。こうすることで、POP が消えたことによってメイン表示部分が上に移動する(ように見える)
こういう処理になるように StatefulWidget を作っただけです。
コード
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { bool _isTapClose = false; void _onTapCloseButton() { setState(() { _isTapClose = true; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Stack( children: <Widget>[ Container( margin: EdgeInsets.only(top: (_isTapClose ? 0.0 : 50.0)), color: Colors.yellow, child: getList()), (_isTapClose ? Container() : UpperPop()), ], )); } Widget UpperPop() { final TextStyle textStyle = TextStyle(fontSize: 20); final TextStyle textButtonStyle = TextStyle(fontSize: 20, color: Colors.blue); final Size displaySize = MediaQuery.of(context).size; return Container( height: (50), width: displaySize.width, child: Row( children: <Widget>[ Expanded(child: Text('Upper Pop Test', style: textStyle)), FlatButton( onPressed: () { _onTapCloseButton(); }, child: Text( "Close", style: textButtonStyle, ), ), ], )); } Widget getList() { return ListView(children: <Widget>[ Text('Item'), ]); } }
ここからの発展
あとは、POP部分やメイン部分に好きな Widget を配置すればいいでしょう。
Stack に乗せているのはなぜかというと、メイン表示部分がリストのようにスクロールする場合に、POP部分が一緒にスクロールされないように(画面上に固定されているように)するためです。
アニメーションを使ってPOP部分が上にニュッと消えるようにするのもカンタンにできそう。