Flutter グラデーションいろいろ 🎨

## 🏹 TL;DR

Flutter でのグラデーションの設定方法をまとめました。
サンプルコード、表示イメージを用意していますので、利用用途にマッチするものがあればコピペして使ってください。

また、「 **ここにグラデーションつけたいんだけど？** 」みたいなのがあれば調べて追記しますので、コメント欄にでもお書きください。


### デフォルトの表示イメージ

新規 Flutter アプリケーションとして用意されているサンプルアプリを利用してグラデーションを施していきます。
![default.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317946/f72673fa-209e-1da6-2e70-788ed63f427a.png)


## AppBar

アプリの上に表示される AppBar にグラデーションを施します。
AppBar には `backgroundColor ` プロパティが用意されていますが、単色でしか設定できないので `gradient_app_bar` パッケージを導入します。

### コードサンプル

`gradient_app_bar` を利用するために `pubspec.yml` ファイルを編集します。

```yml:pubspec.yml
dependencies:
  flutter:
    sdk: flutter

  # https://pub.dev/packages/gradient_app_bar
  gradient_app_bar: ^0.0.1
```


あとは `AppBar` 実装部分を次のように変更するだけ。

```dart
appBar: GradientAppBar(
  title: Text(widget.title),
  backgroundColorStart: const Color(0xffe4a972),
  backgroundColorEnd: const Color(0xff9941d8),
),
```

変更内容をまとめると、

- `AppBar` → `GradientAppBar`
- `backgroundColor` → `backgroundColorStart` と `backgroundColorEnd`

です。

シンプルなパッケージなので、グラデーションの向き（左上から右下など）は変更できません。


### 表示イメージ

![app_bar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317946/afdaccf9-9ef5-56ed-e66e-bda5526fcef9.png)


## body

アプリの `body` 、つまりメインとなるウィジェットの背景色をグラデーションする方法です。

大雑把に説明するとグラデーションしているのは `BoxDecoration` で `Container` をデコレーションしています。
もともと `body` に設定していたウィジェットは、その `Container` の子要素として設定します。


### コードサンプル

```dart
body: Container(
  height: double.infinity,
  width: double.infinity,
  decoration: BoxDecoration(
    gradient: LinearGradient(
      begin: FractionalOffset.topLeft,
      end: FractionalOffset.bottomRight,
      colors: [
        const Color(0xffe4a972).withOpacity(0.6),
        const Color(0xff9941d8).withOpacity(0.6),
      ],
      stops: const [
        0.0,
        1.0,
      ],
    ),
  ),
  child: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text(
          'You have pushed the button this many times:',
        ),
        Text(
          '$_counter',
          style: Theme.of(context).textTheme.display1,
        ),
      ],
    ),
  ),
),
```

もともと `body` に設定していた `Center` を、そのままグラデーションされた `Container` の `child` にしてやれば OK です。



### 表示イメージ

![body.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317946/12022afe-ef1c-0279-73f0-3692fa6fa39a.png)




## FloatingActionButton

右下に表示されているいかにもマテリアルデザインって感じの `FloatingActionButton`。
これもグラデーションすることができます。

やり方は `body` のときと同じで、 `BoxDecoration` でデコレーションされた `Container` でラップしてやります。


### コードサンプル

```dart
floatingActionButton: FloatingActionButton(
  onPressed: _incrementCounter,
  tooltip: 'Increment',
  child: Container(
    height: double.infinity,
    width: double.infinity,
    decoration: BoxDecoration(
      shape: BoxShape.circle,
      gradient: LinearGradient(
        begin: FractionalOffset.topLeft,
        end: FractionalOffset.bottomRight,
        colors: const [
          Color(0xffe4a972),
          Color(0xff9941d8),
        ],
      ),
    ),
    child: Icon(Icons.add),
  ),
),
```

もともと `floatingActionButton` の `child` に設定していた `Icon` を、そのままグラデーションされた `Container` の `child` にしてやれば OK です。


### 表示イメージ

![floating_action_Button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317946/547b7701-2caf-87c1-d835-fa5f61aa5149.png)


## テキスト

力技ではありますが、アプリに表示されるテキストにもグラデーションを施すことが可能です。


### コードサンプル

まずはテキストのスタイルに設定するための `Shader` を用意します。

サンプルアプリでは `_MyHomePageState` の `build` メソッドの頭にでも追加してやればいいと思います。

```dart
final Shader _linearGradient = LinearGradient(
  colors: <Color>[
    Color(0xff1A2980),
    Color(0xff26D0CE),
  ],
).createShader(
  Rect.fromLTWH(
    0.0,
    0.0,
    250.0,
    70.0,
  ),
);
```

`BoxDecoration` のときとは異なり、座標指定で作成した `Shader` を文字に重ねているので、フォントサイズの変更などに柔軟に対応する場合は、ひと手間いりそうです。
（参考にサイトを下にまとめていますが、そちらでは座標を計算してくれるメソッドなども書かれていました）
<br>
あとはグラデーションしたい `Text` にスタイル設定してやれば OK 。

```dart
Text(
  'You have pushed the button this many times:',
  style: new TextStyle(
    fontSize: 32.0,
    fontWeight: FontWeight.bold,
    foreground: Paint()..shader = _linearGradient),
),
```

`foreground: Paint()..shader = _linearGradient` のところで用意した `Shader` を設定しています。
※表示イメージが見やすいようにフォントサイズも大きくしています


### 表示イメージ

![text.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317946/f8955532-af3e-8bea-cb8b-079c717e65b6.png)


## まとめ

グラデーション好きーな僕ですが、普段やってる CSS などでの実装に比べて少し手間に感じました。
また、コンポーネントごとに実装方法も異なるので、もう少しシンプルに統一された実装ができるようになればな……、という感じです。
<br>
一応、今回のソースコードを GitHub にあげていますので、興味のある方はどうぞ。
:octocat: [azukisiromochi/gradient_sample | GitHub](https://github.com/azukisiromochi/gradient_sample)
<br>
この記事はグラデーションを使いたい人のために随時更新していくつもりですので、グラデーションの設定方法がわからないものがあればお伝え下さい！
それでは、良い Flutter & グラデーションライフを～ :yum:

2021/1/27 追記
コメントにもやり取りがありますが、 Flutter で CSS のようにグラデーションを書く方法を記事にまとめました。
よかったらあわせてどーぞ！

:link: [Flutter で CSS ライクにグラデーションを書く方法 🎨](https://qiita.com/azukisiromochi/items/c4812c6f0a52459a9b0b)

## 参考にしたサイト

:link: [Flutter: How to Use Gradients and the GradientAppBar Plugin](https://alligator.io/flutter/flutter-gradient/)

:link: [How to add Floating action Button in Bottom Navigation Bar in Center with border? | Stack Overflow](https://stackoverflow.com/questions/57917876/how-to-add-floating-action-button-in-bottom-navigation-bar-in-center-with-border)

:link: [Gradient text in Flutter | Medium](https://medium.com/@tonyowen/gradient-text-in-flutter-24a8c8adfcd9)