Flutter Drawer(ドロワー) tips

## はじめに

FlutterのDrawer(ドロワー)[^1]について調べたことを書きます。基本構成は公式[^2]に任せます。

## 実装

### コード側の処理によって開く[^4]
デフォルトで実装されるメニューボタンから別のボタンに変えたい時に使えます。以下のどちらかを使えば実装できます。

```dart
_key.currentState.openDrawer() 
```

```dart 
Scaffold.of(context).openDrawer()
```
コード内ではボタンによってドロワーが開く様になっています。

```dart
  final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        key: _key,
        drawerEdgeDragWidth: 0, //　ボタンのみでドロワーを開ける様にする(スワイプでドロワーを開けるエリアを0にする）
        drawer: Drawer(),
        appBar: AppBar(
          automaticallyImplyLeading: false, // デフォルトで設置されるメニューボタンを表示させない
        ),
        body: Center(
            child: RaisedButton(
          child: Text('open'),
          onPressed: () => _key.currentState.openDrawer(),
        )));
  }
```

### コード側の処理によって閉じる[^2][^5]
Navigatorを使えば実装できます。

```dart
Navigator.pop(context)
```

コード内ではIconButton(X)のタップでドロワーが閉じるようにしています。

```dart

 final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        key: _key,
        drawerEdgeDragWidth: 0, //　ボタンのみでドロワーを開ける様にする(スワイプでドロワーを開けるエリアを0にする）
        drawer: Drawer(
            child: ListView(
                // Important: Remove any padding from the ListView.
                padding: EdgeInsets.zero,
                children: <Widget>[
              DrawerHeader(
                  child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text('Drawer Header'),
                        IconButton(
                          icon: const Icon(Icons.close),
                          onPressed: () => Navigator.pop(context),
                        )
                      ]),
                  decoration: BoxDecoration(
                    color: Colors.blue,
                  ))
            ])),
        appBar: AppBar(
          automaticallyImplyLeading: false, // デフォルトで設置されるメニューボタンを表示させない
        ),
        body: Center(
            child: RaisedButton(
          child: Text('open'),
          onPressed: () => _key.currentState.openDrawer(),
        )));
  }
```

### バックボタンで閉じる[^5]
Androidだとバックボタンでドロワーを閉じたい時があると思います。その時はScaffoldをWillPopScopeで囲って上げます。

```dart
  final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
        onWillPop: () {
          bool isDrawerOpen = _key.currentState.isDrawerOpen;
          if (isDrawerOpen) {
            Navigator.pop(context);
            return Future.value(false); // 画面遷移をさせない
          } else {
            return Future.value(true); // 画面遷移を許可
          }
        },
        child: Scaffold(...)); // drawerの中身
  }
```

### 幅を設定する[^6]
drawerが開いたときの幅を設定します。SizedBoxなどの幅を設定できるWidgetで囲ってあげます。

```dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        drawer: SizedBox(width: 100, child: Drawer()), // 幅が100になる
        appBar: AppBar(),
  }
```
------
実装自体と関係ないですがDrawer自体は開発者としては便利ですが、中の項目が隠れてしまい別の画面に遷移するのに一手間かかる[^3]ので実装する際に考慮する必要はあるようです。


[^1]: https://www.pinterest.jp/christianwatson/android-navigation-drawer/

[^2]: https://flutter.dev/docs/cookbook/design/drawer
[^3]: [はじめてのUIデザイン](https://peaks.cc/books/ui_design)
[^4]: [Flutter: How to open Drawer programmatically](https://stackoverflow.com/questions/57748170/flutter-how-to-open-drawer-programmatically)
[^5]: [How to Close Scaffold Drawer programmatically](https://stackoverflow.com/questions/57267908/how-to-close-scaffold-drawer-programmatically?rq=1)
[^6]: [adding width to drawer in flutter](https://stackoverflow.com/questions/57332430/adding-width-to-drawer-in-flutter)