Flutter/DartでBitfinexのレンディングアプリを作る(Part3 グラフ描画/ファイル分割/設計書/アイコン)

---
# :book: Flutterの記事を整理し本にしました :book:
https://zenn.dev/kazutxt/books/flutter_practice_introduction

* <font color="red"><b>本稿の記事を含む様々な記事を体系的に整理し本にまとめました</b></font>
* 今後はこちらを最新化するため、<font color="red"><b>最新情報はこちらをご確認くださ</b>い</font>
* 10万文字を超える超大作になっています(笑)

---

# はじめに
* この記事は、初めてのスマホアプリを作るまでの軌跡を残したものです。
* この記事では、グラフ描画/画面とロジックの分離/ワイヤーフレームの設計書/アイコン作成を紹介します


## 関連記事
* [Flutter/DartでBitfinexのレンディングアプリを作る(Part1 インストールと画面作成/画面遷移)](https://qiita.com/kazutxt/items/e4f3bbb4d8b301f4141c)
* [Flutter/DartでBitfinexのレンディングアプリを作る(Part2 stateful/データの永続化)]
(https://qiita.com/kazutxt/items/c114bb6f6bf6969cfa58)
* [Flutterの"Widget of the Week"がめっちゃ勉強になったので、まとめてみた](https://qiita.com/kazutxt/items/10355961ee2fa3a65023)

# グラフ描画
* chartsというライブラリを使えば、棒グラフ、円グラフ、折れ線グラフ等々が簡単に作れます
     * [ExampleGallery](https://google.github.io/charts/flutter/gallery.html)
* アニメーションもつけられます
* 最初にパッケージを読み込みます

``` pubspec.yaml
dependencies:
    charts_flutter: "^0.9.0"
```
  
* 各画面で、グラフの作成を行いますが、基本的な流れは同じです
    1. データ列をList形式で集める
    2. グラフ用データ列に1のデータを入れ、要素のデータや日付をマッピングする
    3. グラフに2のデータをいれ、凡例やオプションやサイズ等の設定をおこなう
        
## グラフのイメージ

![graph2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/b9877aa6-2dfa-54c2-7698-3b123105c919.png)

## 円グラフ

``` pie.dart
//ベースになるクラス
class BalanceCurrency {
  String name;
  String value;
  Color colorVal;
  BalanceCurrency(this.name, this.value, this.colorVal);
}

//円グラフで表示する3つのデータを定義
var usddata = [
        new BalanceCurrency("Provided", usdProvided.toStringAsFixed(0),
            Color.fromRGBO(0xf0, 0, 0, 1.0)),
        new BalanceCurrency("Offer", usdOffer.toStringAsFixed(0),
            Color.fromRGBO(0xf0, 0, 0, 0.5)),
        new BalanceCurrency("free", usdFree.toStringAsFixed(0),
            Color.fromRGBO(0x7F, 0x7F, 0x7F, 1.0)),
      ];


//グラフ用Listにデータをたす。クラスとグラフ化データのマッピングを行う
List<charts.Series<BalanceCurrency, String>> _serieseUSDData = new List<charts.Series<BalanceCurrency, String>>();

_serieseUSDData.add(
  charts.Series(
    data: usddata,
    domainFn: (BalanceCurrency currency, _) => currency.name,
    measureFn: (BalanceCurrency currency, _) => int.parse(currency.value),
    colorFn: (BalanceCurrency currency, _) =>
      charts.ColorUtil.fromDartColor(currency.colorVal),
    id: "usdBalanceCurrency",
    labelAccessorFn: (BalanceCurrency row, _) => '${row.value}',
    ),
);

//グラフの定義
pcUSD = charts.PieChart(
        _serieseUSDData,
        animate: true,
        animationDuration: Duration(seconds: 1),
        behaviors: [ /* 省略 */],
        defaultRenderer: new charts.ArcRendererConfig(/* 省略 */),
);
```

## 折れ線グラフ

``` timechart.dart
//ベースになるクラス
class Rate {
  DateTime date;
  String currency;
  double rate;
  Color colorVal;

  Rate(this.date, this.currency, this.rate, this.colorVal);
}

//クラスのリスト
List<Rate> usdDailyList = [];

//データの詰め込み(ループの中で必要な情報を加工して詰める部分を抜粋)
//実際は線の本数分ありますが、例示は1つだけなのでご注意ください
usdDailyList.add(new Rate(dt, "USD", double.parse(lineData[1]),
          Color.fromRGBO(0xf0, 0, 0, 1.0)));

//グラフ用Listにデータをたす。クラスとグラフ化データのマッピングを行う
//実際は線の本数分ありますが、例示は1つだけなのでご注意ください
List<charts.Series<Rate, DateTime>> _serieseData = new List<charts.Series<Rate, DateTime>>();

_serieseData.add(
  charts.Series<Rate, DateTime>(
    id: "USD",
    data: usdDailyList,
    domainFn: (Rate rate, _) => rate.date,
    measureFn: (Rate rate, _) => rate.rate,
    colorFn: (Rate rate, _) =>
        charts.ColorUtil.fromDartColor(rate.colorVal),
      ),
    );

//グラフの定義
charts.TimeSeriesChart tsc = charts.TimeSeriesChart(
  _serieseData,
  animate: true,
  animationDuration: Duration(seconds: 1),
  behaviors: [
    charts.SeriesLegend(
      position: charts.BehaviorPosition.bottom,
      desiredMaxColumns: 3,
    )
  ],
);
```

## 棒グラフ
``` bar.dart
//ベースになるクラス
class InterestData {
  String date;
  double val;
  Color colorVal;

  InterestData(this.date, this.val, this.colorVal);
}

//クラスのリスト
List<Rate> usdDailyList = [];

//グラフ用Listにデータをたす。クラスとグラフ化データのマッピングを行う
//idと日付によって、同じリストの通貨別、日別を識別するようです
 List<charts.Series<InterestData, String>> _serieseData = new List<charts.Series<InterestData, String>>();

_serieseData.add(
  charts.Series(
   id: key + "usd",
   data: [new InterestData(key, double.parse(usdValue), Color.fromRGBO(0xf0, 0, 0, 1.0))],
   domainFn: (InterestData interest, _) => interest.date,
   measureFn: (InterestData interest, _) => interest.val,
   fillPatternFn: (_, __) => charts.FillPatternType.solid,
   fillColorFn: (InterestData interest, _) =>           charts.ColorUtil.fromDartColor(interest.colorVal),
  ),
);
//グラフの定義
charts.BarChart bc = charts.BarChart(
   _serieseData,
   animate: true,
   barGroupingType: charts.BarGroupingType.grouped,
   animationDuration: Duration(seconds: 1),
   defaultRenderer: new charts.BarRendererConfig(
     groupingType: charts.BarGroupingType.stacked, strokeWidthPx: 2.0),
 );
```

# 画面とロジックの分離
* 処理の分け方は、一般的にはデザインパターンなどと呼ばれ、MVCなどがあります。
    * はっきり言って作りたいものに合ったものを選定するに限るのですが、現時点では生まれたばかりで構造も流動的て、まだPoCの粋を出ないので、なんちゃってです。
    * 1ファイルで作るのに限界が出てきたので分けましたというお話


![div.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/92e3f2bd-3b26-8a53-02ab-82a3a5584fd1.png)

* 本来もう少し細かくModel,View,Controllerやレイヤーを意識して分けるのでしょうが、今回は一旦ここまでにしました。
    * 結合度が下がり、1ファイルが小さくなり、責任範囲が明確になり、冗長がぐんと減りました。
* きれいに整頓するっていいですね。
    * ただ、この手のリファクタリングはいつも迷うｗ


# 設計書
* 画面の見やすさを作っているうちに、画面の要素の比率などを気にするようになりました。
    * たまにはみ出したりするので、絶対値でしている箇所がないかを確認する意味も込めてです
    * 一般的にはワイヤーフレームなどで画面イメージを作るのでしょうが、Excelで作るのは嫌
    * ということで探した結果、いくつか候補があったのですが、いつの間にかアカウントをもっていた、`cacoo`に決定
    * https://cacoo.com/ja/
        * すぐにチームの有料プランの無料トライアルにリダイレクトされてイラっとするのですが、きちんと個人の無料版もあります
        * プロプランのフリーの部分になります。
            * https://cacoo.com/ja/signup

## 設計書イメージ
![cacoo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/bc86db8a-0e5c-254c-76e6-c93400f8dc97.png)

* 使い勝手はかなりいい感じです。
    * 日本語ですしショートカットも使えますし、アイコンなどが少ないのは少し気になりますが

# アイコン
* スマホアプリのランチャーアイコンをオリジナルのものにしたいですよね
    * まず、アイコンを画像ファイルとして作成します
        *  一旦仮です。センスがないｗ

<img width="300px" alt="icon.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/b2ceaead-a47b-7278-bc34-2f6ee265da8e.png">


* アプリへの組み込みは `flutter_launcher_icon`という便利なライブラリがあるので、こちらを使います
    * ライブラリの設定とiconのパスを指定します

``` pubspec.yaml
dev_dependencies:
    flutter_launcher_icons:"^0.7.5"
flutter_icons:
    android: true
    ios: true
    image_path: "assets/icon/icon.png"

```
* 筆者は上記だけで良いと思って下を読み飛ばしていたので、少しだけ躓いたのですが、下記のコマンドも実行する必要があります。

``` 
$ flutter pub get
$ flutter pub pub run flutter_launcher_icons:main
```

* アイコンが変わりました

<img width="300px" alt="Screenshot_20200914-133156.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/ae5ba95e-f7fa-d1db-2472-8e697fd7cc84.png">