Cardで四隅からはみ出さないようにする

[Card](https://api.flutter.dev/flutter/material/Card-class.html)を使ってみた。

## 問題
Cardのchildに指定したものが、Cardの四隅からはみ出る。。

## 試したこと

コードはこんな感じで非常にシンプル。128x128のCardを2つ作成。
一つ目は何も指定なしのContainerを入れたCard, 二つ目はContainer(color=yellow)を入れたCardです。

```dart
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox.fromSize(
            size: Size(128, 128),
            child: Card(
              child: Container(),
            ),
          ),
          SizedBox.fromSize(
            size: Size(128, 128),
            child: Card(
              child: Container(
                color: Colors.yellow.withOpacity(0.5),
              ),
            ),
          ),
        ],
      ),
    );
  }
```

Simulatorでみると、まあ問題ない。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375661/da4d5e41-5c4d-a46a-cfd8-8b0a19e8938b.png" width=300>

だけど拡大してみると、Cardの4隅がはみ出ている。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375661/9f61d0b2-0965-aa08-75c3-4233a17d6058.png)

結局このような感じでCardの中のContainerでdecoracationを指定するとはみ出ないだろう・・・と思った。

```dart
final shape = CardTheme.of(context).shape ?? const RoundedRectangleBorder(
  borderRadius: BorderRadius.all(Radius.circular(4.0)),
);
...
SizedBox.fromSize(
  size: Size(128, 128),
  child: Card(
    color: Colors.white,
    shape: shape,
    child: Container(
      decoration: ShapeDecoration(
        shape: shape,
        color: Colors.yellow.withOpacity(0.5),
      ),
      child: Column(
        children: [
          Container(height: 36, color: Colors.blue),
        ],
      ),
    ),
  ),
),
```

これで解決なのかと思ったら Container -> child に指定したものがはみ出る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375661/d458d23b-90ef-6d38-c893-7f23e7cf521e.png)

なんなのこれ。。

## 解決

https://stackoverflow.com/questions/55316539/rounded-corner-card-widget-with-right-border-in-flutter を参考にしてClipPathでくくったら解決した。

```dart
final shape = CardTheme.of(context).shape ?? const RoundedRectangleBorder(
  borderRadius: BorderRadius.all(Radius.circular(4.0)),
);
...
SizedBox.fromSize(
  size: Size(128, 128),
  child: Card(
    color: Colors.white,
    shape: shape,
    child: ClipPath(
      clipper: ShapeBorderClipper(
        shape: shape,
      ),
      child: Container(
        color: Colors.yellow.withOpacity(0.5),
        child: Column(
          children: [
            Container(height: 36, color: Colors.blue),
          ],
        ),
      ),
    ),
  ),
),
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375661/445be625-5668-1529-a7b2-9148377fb4eb.png)

試してないけど、Cardじゃなくても同じようなことが言えるんだろうなあ。

## （12/6追加）解決その2

Cardに `clipBehavior` というパラメータがありそれでも解決できることがわかった。

`Clip.antiAliasWithSaveLayer` は非常に遅いというのが書いてあるので、ひとまず`hardEdge`と `antiAlias` を試してそれぞれの左上の隅を確認してみた。
Macのプレビューアプリを使い拡大してみた結果です。
左から`hardEdge`, `antiAlias`, `ClipPath`を使った例, 何もchildを含めないCardの順です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375661/9ad61c04-22d1-1550-fd52-f76724664937.png)

これをみると、ドキュメント通りやはり`hardEdge`は荒い。拡大しなくてもその荒さがわかるぐらい。
一方、`antiAlias`, `ClipPath`を使った例、この2つはあまり遜色なかった。
どっちでもいいけど手軽さやメンテナンス性を考えると`antiAlias`を使う方が圧倒的に良いと考える。

`ClipPath`を使った実装は、後から見た人はなぜこういう作りにしている？と疑問に思いそうなので。