[Flutter] モーダル(Modal)の作り方

Flutterには、showModalBottomSheetとshowDialogという2つのメソッドがあります。どちらもモーダルを表示するために使用されますが、それぞれ独自の特徴があります。ここでは、それぞれのメソッドでモーダルを作成し、モーダルを閉じるための2つの異なる方法について説明します。

目次

showModalBottomSheetを使ったモーダルの作成

基本的な使い方

showModalBottomSheetを使用して、モーダル外をタップしてもモーダルを閉じることができるサンプルコードは以下のとおりです。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Scaffold Widget Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Show Modal'),
          onPressed: () {
            _showModal(context);
          },
        ),
      ),
    );
  }
}

void _showModal(BuildContext context) {
  showModalBottomSheet<void>(
    context: context,
    builder: (BuildContext context) {
      return Container(
        height: 400,
        child: SingleChildScrollView(
            child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            const ListTile(
              leading: Icon(Icons.music_note),
              title: Text('Music'),
              subtitle: Text('Select your favorite music'),
            ),
            const ListTile(
              leading: Icon(Icons.photo_album),
              title: Text('Photos'),
              subtitle: Text('Select your favorite photos'),
            ),
            const ListTile(
              leading: Icon(Icons.videocam),
              title: Text('Video'),
              subtitle: Text('Select your favorite video'),
            ),
            ElevatedButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Close'),
            ),
          ],
        )),
      );
    },
  );
}

モーダル以外のタップしてもモーダルが閉じないようにする方法

showModalBottomSheetメソッドには”isDismissible”というプロパティがあります。このプロパティをfalseで設定することで、モーダル以外をタップしても、モーダルが閉じないようになります。

void _showModal(BuildContext context) {
  showModalBottomSheet<void>(
    context: context,
    isDismissible: false, // (追加)ユーザーがモーダルを閉じないようにする
    builder: (BuildContext context) {
      return Container(
        height: 400,
        child: SingleChildScrollView(
            child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            const ListTile(
              leading: Icon(Icons.music_note),
              title: Text('Music'),
              subtitle: Text('Select your favorite music'),
            ),
            const ListTile(
              leading: Icon(Icons.photo_album),
              title: Text('Photos'),
              subtitle: Text('Select your favorite photos'),
            ),
            const ListTile(
              leading: Icon(Icons.videocam),
              title: Text('Video'),
              subtitle: Text('Select your favorite video'),
            ),
            ElevatedButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Close'),
            ),
          ],
        )),
      );
    },
  );
}

showDialogを使ったモーダルの作成

基本的な使い方

showDialogを使用する場合、以下のように、GestureDetectorでタップイベントをキャッチして、closeメソッドを呼び出すコードを実装することができます。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Scaffold Widget Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Show Modal'),
          onPressed: () {
            _showDialog(context);
          },
        ),
      ),
    );
  }
}

void _showDialog(BuildContext context) {
  showDialog<void>(
    context: context,
    builder: (BuildContext context) {
      return GestureDetector(
        onTap: () => Navigator.pop(context),
        child: Dialog(
          child: Container(
            width: double.infinity,
            padding: const EdgeInsets.all(20.0),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text('Do you want to delete this item?'),
                SizedBox(height: 20),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    ElevatedButton(
                      onPressed: () {},
                      child: Text('Yes'),
                    ),
                    ElevatedButton(
                      onPressed: () => Navigator.pop(context),
                      child: Text('No'),
                      style: ElevatedButton.styleFrom(
                          foregroundColor: Colors.red,
                          backgroundColor: Colors.green[100]),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      );
    },
  );
}

モーダル以外のタップしてもモーダルが閉じないようにする方法

showDialogメソッドには”barrierDismissible”というプロパティがあります。このプロパティをfalseで設定することで、モーダル以外をタップしても、モーダルが閉じないようになります。

void _showDialog(BuildContext context) {
  showDialog<void>(
    context: context,
    barrierDismissible: false, // (追加)ユーザーがモーダルを閉じないようにする
    builder: (BuildContext context) {
      return GestureDetector(
        onTap: () => Navigator.pop(context),
        child: Dialog(
          child: Container(
            width: double.infinity,
            padding: const EdgeInsets.all(20.0),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text('Do you want to delete this item?'),
                SizedBox(height: 20),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    ElevatedButton(
                      onPressed: () {},
                      child: Text('Yes'),
                    ),
                    ElevatedButton(
                      onPressed: () => Navigator.pop(context),
                      child: Text('No'),
                      style: ElevatedButton.styleFrom(
                          foregroundColor: Colors.red,
                          backgroundColor: Colors.green[100]),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      );
    },
  );
}

まとめ

FlutterでModalを作成する方法として、showModalBottomSheetとshowDialogがあります。画面のどこをタップしてもモーダルを閉じる場合は、showModalBottomSheetではNavigator.popメソッドを呼び出すコールバック関数を、showDialogではGestureDetectorでタップイベントをキャッチしてNavigator.popメソッドを呼び出すコードを実装することができます。一方、モーダル画面で操作しないとモーダルを閉じない場合は、showModalBottomSheetではモーダル内のコードにNavigator.popメソッドを呼び出すUIを含める必要があり、showDialogではダイアログ内のコードにNavigator.popメソッドを呼び出すUIを含める必要があります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次