【Flutter】percent_indicator の使い方

##  初めに
percent_indicator とは、以下の画像のように何らかの達成状況を示すための Widget です。
家計簿のアプリや習慣化のアプリに多く使用される印象です。
<img width=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/34d1dae3-dff6-3d1a-e9d5-f720474a49ba.png">

## 準備
まずは、[percent_indicator パッケージ](https://pub.dev/packages/percent_indicator) を「 pubspeck.yaml 」に記述します。
パッケージのバージョンは、特に制約がなければ最新のバージョンで問題ありません。

```yaml: pubspeck.yaml
dependencies:
  flutter:
    sdk: flutter

  percent_indicator: ^4.2.2
```
Pub get をして準備は完了です。

## 実装
まずは実装したい画面で percent_indicator をインポートします。

```dart:main.dart
import 'package:percent_indicator/percent_indicator.dart';
```

percent_indicator には以下の二種類が用意されています。
+ CircularPercentIndicator
+ LinearPercentIndicator

## CircularPercentIndicator
CircularPercentIndicator とは円型のインジケーターのことです。
一番初めに提示した画像と同じインジケーターです。

以下のように記述すると、画像のような CircularPercentIndicator が表示されます。

```dart: main.dart
CircularPercentIndicator(
  radius: 60.0,
  lineWidth: 5.0,
  percent: 0.5,
  center: const Text("50%"),
  progressColor: Colors.green,
),
```
<img width=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/bc6f945b-b076-e3e5-0f43-3f7b443f028d.png">

### radius
radius は CircularPercentIndicator の円の大きさ、正確には円の半径を指定するためのプロパティです。 int 型、 double 型、または MediaQuery を使った指定も可能です。

### lineWidth
lineWidth は文字通り、インジケーターの線の太さを指定するためのプロパティです。
<img width=250, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/a0a9228e-c680-7662-5bee-f37878649094.png"><img width=250, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/1200ad8d-4e26-8948-24e8-ee1336f0de58.png">

左の画像は `lineWidth: 2.0,`　右の画像は `lineWidth: 5.0,`
にしたものです。明らかに線の太さが変化していることがわかります。

### percent
percent はインジケーターのパーセントを指定するためのプロパティです。
double 型で、 0 ~ 1 の値で指定します。 0 ~ 100 ではないことに注意しましょう。

### center
center では CircularPercentIndicator の円の中心に配置する Widget を指定します。
テキストだけでなく、以下の画像のようにアイコンを指定することも可能です。
<img width=250, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/fc5d8971-87eb-4d44-5904-98f824aef579.png">

### progressColor
progressColor は進捗部分の色を指定するためのプロパティです。上の画像では Colors.green に指定していますが、デフォルトでは Colors.red に設定されています。

### backgroundColor
backgroundColor は進捗部分以外の部分、未達成の部分の色を指定するためのプロパティです。
以下の画像のように色を変更することができます。
指定しなければ灰色に近い色になります。
<img width=250, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/415faef5-3b7c-aa8f-fa74-bbb72048c355.png">

### backgroundWidth
backgroundWidth はインジケーターの背景の線の太さを指定するためのプロパティです。
以下のように、進捗部分の線よりも太くすることも可能です。
<img width=250, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/0da33120-00dd-da09-e1b3-b9fa933c5f72.png">

### header
header ではインジケーターの上部に表示させる Widget を指定します。
下の画像では header に「Homework」というテキストを指定し、 center にアイコンを指定することで、宿題の進捗状況を示すインジケーターを表示しています。
<img width=250, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/22b62164-82bd-89f2-4ffa-15c27e5c647d.png">
このように、 header にはインジケーターの内容を明らかにする役割があります。

### footer
footer ではインジケーターの下部に表示させる Widget を指定します。
下の画像では先ほど作成したインジケーターの footer にパーセントの表示を追加することでより視覚的にわかりやすいインジケーターにしています。
<img width=250, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/396eb31a-1440-a939-d89d-a5cfbfd4b6ba.png">

### animation
animation は以下のように、インジケーターが読み込まれた際のアニメーションをつけるためのプロパティです。
デフォルトでは false になっていますが、true にするとアニメーションが適用されます。
![percent_indicator_animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/e29c0fbe-0378-9ef1-e7b0-632df64243d1.gif)

### animationDuration
animationDuration は animation が true の時、アニメーションが終わるまでの時間を指定するためのプロパティです。 int 型のミリ秒 (ms) で指定します。

## LinearPercentIndicator
LinearPercentIndicator とは以下の画像のように、直線のインジケーターのことです。

```dart:main.dart
LinearPercentIndicator(
  width: 140.0,
  lineHeight: 14.0,
  percent: 0.5,
  backgroundColor: Colors.grey,
  progressColor: Colors.blue,
),
```

<img width=300, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/90449149-0d34-e3d9-3cc7-6a07cab39f96.png">

### width
width は LinearPercentIndicator の幅を指定するためのプロパティです。

### lineHeight
lineHeight は LinearPercentIndicator の高さを指定するためのプロパティです。

### center
center は CircularPercentIndicator と同様に、インジケーターの内部に表示する Widget を指定するためのプロパティです。
以下の画像では center にテキストを指定しています。
<img width=300, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/08bc434c-d1f8-f01b-4e7f-65a8fe001c30.png">

### leading
leading は LinearPercentIndicator の左側に配置する Widget を指定するためのプロパティです。
下の画像ではアイコンを指定しています。
<img width=300, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/6fb6015a-4acb-188b-d4c1-54297b49d59e.png">

### trailing
trailing は LinearPercentIndicator の右側に配置する Widget を指定するためのプロパティです。
下の画像ではテキストを指定しています。
<img width=300, height=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/b4e7d2f7-b674-2f4e-eec9-dc3c5f9919ed.png">

その他のプロパティは CircularPercentIndicator と比較して同じものも多いため、省略します。

## indicator を動かす
最後に Riverpod を使って CircularPercentIndicator を動かしてみましょう。

```dart: main.dart
final percentProvider = StateProvider<double>((ref) => 0.0);
```
まずは CircularPercentIndicator の percent に代入する値を監視するための StateProvider を作成し、 `percentProvider` という変数に代入します。
<br>

```dart: main.dart
final percentNotifier = ref.watch(percentProvider.notifier);
final percent = ref.watch(percentProvider);
```
次に、 percent の状態を読み取り、 `percentNotifier` `percent` 変数に代入します。
<br>

```dart: main.dart
CircularPercentIndicator(
  radius: 60.0,
  lineWidth: 5.0,
  percent: percent,
  center: const Text("Homework"),
  progressColor: Colors.green,
),
```
CircularPercentIndicator の percent プロパティに先ほどの `percent` 変数の値を指定します。
こうすることで、 `percent` の値が変更された際にその変更が反映されるようになります。
<br>

```dart: main.dart
ElevatedButton(
  onPressed: () {
   percent > 0.9
   ? percentNotifier.state = 0
   : percentNotifier.state = percentNotifier.state + 0.1;
  },
  child: const Text("達成",style: TextStyle(color: Colors.white),),
  style: ElevatedButton.styleFrom(
   primary: Colors.green.shade400
  ),
),
```
次に percent を増加させるための ElevatedButton を設けます。
増加幅は 0.1 にしています。
<br>

```dart: main.dart
percent > 0.9
? percentNotifier.state = 0
: percentNotifier.state = percentNotifier.state + 0.1;
```
このコードでは、ElevatedButton が押された際、 `percent` の値が 0.9 より大きい場合は `percent` の値が 0 に戻り、それ以外は `percent`の値が 0.1 ずつ増加するようにしています。

したがって、 CircularPercentIndicator は以下のように 10% ずつ増加するような挙動になり、 100% になった状態でもう一度ボタンを押すと 0% に戻ります。
![indicator.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609901/3a5ff537-67c8-8e15-f0fd-82f788e20296.gif)



## あとがき
最後まで読んでいただきありがとうございました。


以上です。

参考にしていただければ幸いです。
誤っている箇所があればご指摘いただければ幸いです。

### 参考にしたサイト
https://pub.dev/packages/percent_indicator