FlutterでGradientにopacityを適応させる（foregroundDecoration）

## はじめに

今回、デザインでは左のようなものが要求されていたのにグラデーションの設定をしてみたら右のように...
ちょっとした設定をすれば解決しますが備忘録として記録します。

| ゴールの状態 | 初期の実装 |
|:-:|:-:|
| <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/aa7c2f11-7a21-7d04-86e1-b22e1d88c9b2.png" width="350">  | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/ff2b982e-ccfe-0ab1-ca62-a33a4c6dd321.png" width="350">  |


以下のコードをご覧ください。

```dart
return Scaffold(
  backgroundColor: Colors.black,
  appBar: AppBar(
    backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    title: const Text('デモアプリ'),
  ),
  body: Center(
      child: Container(
    width: 160,
    height: 160,
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(16),
      color: Colors.white,
    ),
  )),
);
```

簡単なレイアウトですが以下のようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/217b298f-9be7-bfdf-972a-8f2c582dcc87.png" width="350">

## グラデーションの適応

では次に、このままグラデーションの適応をしてみましょう。

```dart
return Scaffold(
  backgroundColor: Colors.black,
  appBar: AppBar(
    backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    title: const Text('デモアプリ'),
  ),
  body: Center(
    child: Container(
      width: 160,
      height: 160,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        gradient: const LinearGradient(
          colors: [
            Colors.lightGreenAccent,
            Colors.lightBlueAccent,
          ],
        ),
        color: Colors.white,
      ),
    ),
  ),
);
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/06870789-1aa6-e165-53a5-dbd4b9cba7e4.png" width="350">

## 透明度を設定する

デザインの意向として、グラデーションに透明度の設定をしたい場合があるとします。
では素直に設定してみましょう

```dart
return Scaffold(
  backgroundColor: Colors.black,
  appBar: AppBar(
    backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    title: const Text('デモアプリ'),
  ),
  body: Center(
    child: Container(
      width: 160,
      height: 160,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        gradient: LinearGradient(
          colors: [
            Colors.lightGreenAccent.withOpacity(0.5),
            Colors.lightBlueAccent.withOpacity(0.5),
          ],
        ),
      ),
    ),
  ),
);
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/ff2b982e-ccfe-0ab1-ca62-a33a4c6dd321.png" width="350">

そうですね。
背景が黒なのでこのままでは背景の黒が透けて見えるため暗い印象です。
ではcolorをしてみましょう。

## colorの設定をしてみる

```diff_dart
return Scaffold(
  backgroundColor: Colors.black,
  appBar: AppBar(
    backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    title: const Text('デモアプリ'),
  ),
  body: Center(
    child: Container(
      width: 160,
      height: 160,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        gradient: LinearGradient(
          colors: [
            Colors.lightGreenAccent.withOpacity(0.5),
            Colors.lightBlueAccent.withOpacity(0.5),
          ],
        ),
+        color: Colors.white,
      ),
    ),
  ),
);
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/ff2b982e-ccfe-0ab1-ca62-a33a4c6dd321.png" width="350">

おや、変わりませんね。
そうです。colorとgradientを同時に設定をした場合gradientが優先されるだけです。

## 対策「foregroundDecoration」を併用する

Flutterではよくグラデーション = `Container.decoration`と思いつきますが、`Container`には`foregroundDecoration`というパラメーターが存在します！
今回は`decoration`とかけ合わせて使います。

```dart
return Scaffold(
  backgroundColor: Colors.black,
  appBar: AppBar(
    backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    title: const Text('デモアプリ'),
  ),
  body: Center(
    child: Container(
      width: 160,
      height: 160,
      // 背景側の設定
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        color: Colors.white,
      ),
      // グラデーションの設定
      foregroundDecoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        gradient: LinearGradient(
          colors: [
            Colors.lightGreenAccent.withOpacity(0.5),
            Colors.lightBlueAccent.withOpacity(0.5),
          ],
        ),
      ),
    ),
  ),
);
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/735195/aa7c2f11-7a21-7d04-86e1-b22e1d88c9b2.png" width="350">