【Flutter】Dialogをカスタマイズする

# はじめに
Flutterでダイアログを表示したいと思ったのですが、普通に実装すると以下の三種の選択になってしまいます。

### AlertDialog

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/56ed99c2-c67b-fc63-7e9e-d58296761ee5.png)

### CupertinoDialog

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/e537e482-98fd-5bd4-739e-6bc341f7f3ec.png)

### SimpleDialog

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/c211740b-8c50-7fad-1432-d59580239e23.png)

悪くはないですが、ダイアログもデザインにこだわりたい場合はカスタマイズする必要性があります。
今回は、カスタマイズ方法を記事にしたいと思います。

# カスタマイズ後
先にカスタマイズ後の画像を貼っておきます。
イメージとしてはCupertinoをカスタマイズした風なダイアログです。
（色は適当です）
普通にCupertinoDialogを使うと大きさを変えれなかったり、カスタマイズ性にかけるので`Dialog`で作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/107a2ebf-f165-e261-6955-837302e2b37e.png)

```dart
void _showCustomDialog(BuildContext context) {
    showDialog(
        context: context, builder: (context) => _createCustomDialog(context));
  }

  Dialog _createCustomDialog(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10.0),
      ),
      child: SizedBox(
        width: 300,
        height: 170,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ClipRRect(
              borderRadius: const BorderRadius.only(
                topLeft: Radius.circular(10),
                topRight: Radius.circular(10),
              ),
              child: Container(
                width: 300,
                height: 126,
                decoration: const BoxDecoration(
                  color: Color.fromARGB(255, 210, 225, 192),
                  border: Border(
                    bottom: BorderSide(
                      width: 0.5,
                      color: Color.fromRGBO(0, 0, 0, 0.4),
                    ),
                  ),
                ),
                child: const Center(
                  child: Text("message"),
                ),
              ),
            ),
            Container(
              decoration: const BoxDecoration(
                color: Color.fromARGB(255, 210, 225, 192),
                borderRadius: BorderRadius.only(
                  bottomLeft: Radius.circular(10),
                  bottomRight: Radius.circular(10),
                ),
              ),
              width: 300,
              height: 44,
              child: MaterialButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const SizedBox(
                  height: double.infinity,
                  width: double.infinity,
                  child: Center(
                    child: Text("button"),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
```

# つまずいた点
### 角丸じゃなくなる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/f6035ad7-907b-0960-f250-8dbb6b424217.png)


下記のように、単純にContainerを使うと角丸にはなりません。

```dart

void _showCustomDialog(BuildContext context) {
    showDialog(
        context: context, builder: (context) => _createCustomDialog(context));
  }

  Dialog _createCustomDialog(BuildContext context) {
    return Dialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10.0),
      ),
      child: SizedBox(
        width: 300,
        height: 170,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            //　Containerだけでは角丸にならない。
            Container(
              width: 300,
              height: 126,
              decoration: const BoxDecoration(
                color: Color.fromARGB(255, 210, 225, 192),
                border: Border(
                  bottom: BorderSide(
                    width: 0.5,
                    color: Color.fromRGBO(0, 0, 0, 0.4),
                  ),
                ),
              ),
              child: const Center(
                child: Text("message"),
              ),
            ),
            Container(
              decoration: const BoxDecoration(
                color: Color.fromARGB(255, 210, 225, 192),
                borderRadius: BorderRadius.only(
                  bottomLeft: Radius.circular(10),
                  bottomRight: Radius.circular(10),
                ),
              ),
              width: 300,
              height: 44,
              child: MaterialButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const SizedBox(
                  height: double.infinity,
                  width: double.infinity,
                  child: Center(
                    child: Text("button"),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
```

### 下線の描画と角丸を同時に設定できない
以下のような感じで、BoxDecorationには、場所を指定したborderとborderRadiusを同時にしてはできません。

```dart
Container(
  width: 300,
  height: 126,
  decoration: const BoxDecoration(
    color: Color.fromARGB(255, 210, 225, 192),
    // 線の設定
    border: Border(
      bottom: BorderSide(
        width: 0.5,
        color: Color.fromRGBO(0, 0, 0, 0.4),
      ),
    ),
    // 角丸の設定
    borderRadius: BorderRadius.only(
      bottomLeft: Radius.circular(10),
      bottomRight: Radius.circular(10),
    ),
  ),
  child: const Center(
    child: Text("message"),
  ),
),
```

`Border.all()`なら大丈夫です。

```dart
Container(
  width: 300,
  height: 126,
  decoration: const BoxDecoration(
    color: Color.fromARGB(255, 210, 225, 192),
    // 線の設定
    border: Border.all(color: Colors.black),
    // 角丸の設定
    borderRadius: BorderRadius.only(
      bottomLeft: Radius.circular(10),
      bottomRight: Radius.circular(10),
    ),
  ),
  child: const Center(
    child: Text("message"),
  ),
),
```

では、下線だけ線をつけたい場合はどうすればいいでしょうか？

そういう場合は、`BoxDecoraition`で下線をつけて、角丸は`ClipRRect`で設定します。

```dart
// 角丸はここで設定する
ClipRRect(
  borderRadius: const BorderRadius.only(
    topLeft: Radius.circular(10),
    topRight: Radius.circular(10),
  ),
  child: Container(
    width: 300,
    height: 126,
    // 線はここでつける
    decoration: const BoxDecoration(
      color: Color.fromARGB(255, 210, 225, 192),
      border: Border(
        bottom: BorderSide(
          width: 0.5,
          color: Color.fromRGBO(0, 0, 0, 0.4),
        ),
      ),
    ),
    child: const Center(
      child: Text("message"),
    ),
  ),
),
```