画面の上にポップアップ的なものを表示したい
画面の下に表示したいのなら、ボトムシートがあるのでそれでいいと思います。
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.html
下の 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部分が上にニュッと消えるようにするのもカンタンにできそう。