Flutter/Dart コーディング スタイル

CARTUNEチーム内での Flutter/Dart のコーディングスタイルです。

明文化されていないものもあるので、随時アップデートしていきます！

# Dart

## インデント

2スペース。

```dart
if (hoge) {
  someFunc();
}
```

```dart
someFunc(
  color: Colors.blue,
  fontSize: 16.0,
);
```

継続インデントは4スペース。

```dart
someFunc(
    context, value);
```

IntelliJの場合は Editor > Code Style > Dart > Tabs and Indent から設定する。

- Tab size: 2
- Indent: 2
- Continuation indent: 4
- Keep indents on empty lines: off

### 空行のインデント

空行の場合はインデントを維持しない（スペースを削除する）。

## 改行

引数が1つの場合は、1行で書いてもよい。

```dart
// 引数がchildの1つ
Expand(child: Text('Hello')),
```

引数が2つ以上のWidgetは複数行で書く。

```dart
// 引数がcolor, childの2つ
Container(
  color: Colors.blue,
  child: Text('Hello'), // Textは1行可
),
```

Widgetの引数が1つでも、その子Widgetが複数行の場合は、改行する。
つまり、1行でWidgetを書くのは、Widgetツリーの末端のみとなる。

```dart
// 引数が1つだがchildが複数行なので
// このWidget自身も複数行で書く
Container(
  child: Text(
    'Hello',
    style: TextStyle(fontSize: 16.0),
  ),
),
```

例外的に、EdgeInsetsは複数の引数があっても1行でよい。

```dart
Container(
  padding: EdgeInsets.fromLTRB(1.0, 2.0, 3.0, 4.0),
),
```

また、引数が1つでも、長くなる場合は改行して複数行とする。目安として1行が80文字を超えないことが望ましい。

## 括弧の位置

括弧の終了は、括弧の開始のあとに改行しない場合は、同じ行で閉じる。

```dart
Container(child: Text('Hello')),
```

括弧の開始のあとに改行した場合、中身の最終行の次の行で括弧を閉じる。
なお、インデントはブロック開始時と同じにする。

```dart
Container(
  color: Colors.blue,
  child: Text('Hello'),
), // good
```

```dart
Container(
  color: Colors.blue,
  child: Text('Hello')), // bad
```

関数の呼び出しで「名前なし引数」で開始する場合、同じ行でWidgetの括弧を開始する。
Widgetの閉じる括弧と関数呼び出しの閉じる括弧は同じ行。

```dart
someFunc(Container(
  color: Colors.blue,
  child: Text('Hello'),
));
```

このとき、Widget内の改行については、Widgetの規約に従う。

関数の呼び出しで「名前あり引数」の場合は、Widgetと同様に記述する。

```dart
someFunc(
  foo
  barOption: true,
  title: Text(...), 
);
```

## カンマ

オブジェクトや関数呼び出しの引数で、末尾のカンマは省略せずに記述する。

```dart
Text(
  "Hello, Flutter!",
  style: TextStyle(
    fontSize: 14.0,
    fontWeight: FontWeight.bold, // trailing comma
  ), // trailing comma
),
```

## デフォルト引数

イコールで設定する（推奨）。
※以前のDartではコロンだったが Deprecated のためイコールを使う

```dart
void someFunc({String text = 'Hello'}) {
  ...
}
```

Flutter内では以前からのコロンが使われており、プロジェクト内でも以前に書かれた箇所はコロンを使っているが、新しくコードを書く場合はイコールを使う。

## 文字列

文字列はシングルクォート、ダブルクォートのどちらを使ってもよい。

変数の文字列埋め込みでは、省略が可能な場合でも `{` `}` を記述する（推奨）。日本語の場合は空白なしの文章になることが多く、変数名の区切りが明確でないため。

```dart
"Price is ${price} yen."
```

なお、文字列以外の変数は自動で `toString()` されるので、`toString()` は記述しない。

## コメント

`//` と `/* ... */` はどちらを使ってもよい。

コメント開始 `//` とコメント本文の間は半角スペースひとつ開ける。

```dart
// 前回の読み込みから一定時間が経過していたら
// 自動で再読み込みを行い、最上部へスクロールする
```

コメントの末尾にはピリオドや句点はつけない。

## import

import は以下のグループごとにブロックを分ける。

- Dartコア
- サードパーティのパッケージ
- プロジェクト内の他のパッケージ
- 同じパッケージ

```dart
// dart
import 'dart:core';
import 'dart:async';

// third party
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

// app
import 'package:yourapp/widget.dart';
import 'package:yourapp/text.dart';

// same package
import 'foo.dart';
import 'bar.dart';
```

## クラス

インスタンス変数へのアクセスは、不要な場合は this を使わない。

```dart
// titleはインスタンス変数
Text(title), // OK
Text(this.title), // NG
```

### new / const

オブジェクト生成時の`new` は省略する。`const` は省略しない。

```dart
final child = Container(...);
```

- 以前のFlutterはDart 1だったので `new` が残っているが、新しくコードを書く場合は省略する（推奨）。
- `new` オブジェクト内に、`const` 可能なオブジェクト生成がある場合、宣言なしだと `new` になる説があるので `const` は省略しないで明示的に書く。

## var / final

初期化時の代入以後で変更（再代入）しない変数は、`final`で宣言する（推奨）。

```dart
final value = someFunc();
```

また、型名は省略してよい。
型名があったほうが分かりやすくなると考えられる場合は、型名を記述してもよい。


## 三項演算子

2つの値のどちらかを得るだけの場合など、単純な場合は使用してよい。
結果にさらに式を含まないようにすること。

```dart
// OK
color: android ? Colors.white : Colors.red,

// NG
color: android ? Container(... long ...) : Container(... long ...),
```

三項演算子のなかで使うものをあらかじめ計算するか、別のメソッドなどに切り分ける。

```dart
color: android ? _buildTitleForMaterial() : _buildTitleForCupertino(),
```

## Flutter

### build

`build` メソッドが長くなる場合、その一部を別のメソッドに切り出すとよい（推奨）。

その際は、切り出されたメソッドは  のようになる。

```dart
Widget buildFoo(BuildContext context, Foo foo) {
  ...
}
```

- メソッド名は `build` から始まること
- 第一引数は `BuildContext` であること
- 必要な値を第二引数以降で受け取ること（メンバ変数などをできるだけ避ける）


### ダイアログ

-  ダイアログは閉じるアクションのみを行う
   - API通信や、別の画面を表示することはしない
   - ユーザーの選んだ項目やボタンに応じた値を返すだけ
   - 通信や画面遷移は、ダイアログの結果を受け取った画面が行う

### TextStyle

-  基本のスタイルからのcopyWithは行わない
   - そもそも基本として定義されているスタイルから逸脱するものは、個別に定義する
   - 複数の箇所で使うものがあるのであれば、基本スタイルとして定義する
   - 少なくとも、サイズと太さは変更してはならない
     - 色のみ許可する？