5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Flutter ちょっと Tips 〜画面の上にポップアップを表示する〜

Last updated at Posted at 2019-06-10

画面の上にポップアップ的なものを表示したい

画面の下に表示したいのなら、ボトムシートがあるのでそれでいいと思います。

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ボタンを押したら消えるというヤツです。
banner.gif

考え方

だいぶ泥臭い作り方してます。
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部分が上にニュッと消えるようにするのもカンタンにできそう。

5
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?