Flutter学習5日目 -公式を読む 6. Web開発者のためのFlutter-

**※自分の学習記録のメモとしてこの記事を書いています。**

1日目：[Flutter学習1日目 -公式を読む 1. インストール編-](https://qiita.com/umiremix/items/940f38e03be4b71dc33d)
2日目前編：[Flutter学習2日目前編 -公式を読む 2. エディターの設定編-](https://qiita.com/umiremix/items/0ff6600a6a9f996a3a74)
2日目後編：[Flutter学習2日目後編 -公式を読む 3. テストドライブ編-](https://qiita.com/umiremix/items/f1a84f96199054fbebf2)
3日目: [Flutter学習3日目 -公式を読む 4. スターターFlutterアプリを作成する-](https://qiita.com/umiremix/items/796cc8a7520629cae3b1)
4日目: [Flutter学習4日目 -公式を読む 5. インタラクティブ機能を実装-](https://qiita.com/umiremix/items/abf0a5d4005224cdb083)
5日目：Flutter学習5日目 -公式を読む 6. Web開発者のためのFlutter-（イマココ）

今日はよりFlutterへの理解を深めるために[Learn more](https://flutter.dev/docs/get-started/learn-more)の[Flutter for web developers](https://flutter.dev/docs/get-started/flutter-for/web-devs)を読み進めます！🧜‍♀️

私はWeb開発経験があるためこのページを読み進めますが、他にも

- [Android開発者のためのFlutter](https://flutter.dev/docs/get-started/flutter-for/android-devs)
- [JavaからDartへ codelab](https://codelabs.developers.google.com/codelabs/from-java-to-dart/#0)
- [iOS開発者のためのFlutter](https://flutter.dev/docs/get-started/flutter-for/ios-devs)
- [React Native 開発者のための Flutter](https://flutter.dev/docs/get-started/flutter-for/react-native-devs)
- [Xamarin.Forms 開発者のための Flutter](https://flutter.dev/docs/get-started/flutter-for/xamarin-forms-devs)

があるので、それぞれ学んできた環境に合わせて読み進めるのが良さそうです🙆‍♀️
それでは読み進めていきます👉👉👉

## Web開発者のためのFlutter

このページは、アプリケーションの UI のコンポーネントを配置するための HTML と CSS の構文に精通しているユーザーのためのページです。このページでは、HTML/CSS のコードスニペットを Flutter/Dart のコードに対応させています。

Web レイアウトと Flutter レイアウトの設計の基本的な違いの1つは、制約がどのように機能するか、ウィジェットのサイズや位置をどのように設定するかを学ぶことです。
この例では、次のことを前提としています。

- HTML ドキュメントは <!DOCTYPE html> で始まり、すべての HTML 要素の CSS ボックスモデルは、Flutter モデルとの整合性のために border-box に設定されています。

```css
{
  box-sizing: border-box;
}
```

- Flutter では、"Lorem ipsum" テキストのデフォルトのスタイリングは、構文をシンプルに保つために bold24Roboto 変数で以下のように定義されています。


```dart

TextStyle bold24Roboto = TextStyle(
  color: Colors.white,
  fontSize: 24,
  fontWeight: FontWeight.w900,
);
```

## 基本的なレイアウト操作を行う

### テキストのスタイリングと整列

フォントのスタイルやサイズなど、CSSがフォントやカラーのプロパティで扱うテキスト属性は、`Text`ウィジェットの`TextStyle`の子要素の個別のプロパティです。

```html
<div class="greybox">
    Lorem ipsum
</div>

.greybox {
    background-color: #e0e0e0; /* grey 300 */
    width: 320px;
    height: 240px;
    font: 900 24px Georgia;
}
```

```dart

var container = Container( // grey box
  child: Text(
    "Lorem ipsum",
    style: TextStyle(
      fontSize: 24,
      fontWeight: FontWeight.w900,
      fontFamily: "Georgia",
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 8.47.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/93d44596-97ed-7f90-1abd-418d620fb285.png)

### 背景色の設定

Flutter では、`Container` の `decoration` プロパティを使って背景色を設定します。

CSS の例では、Material カラーパレットに相当する 16 進数の色を使用しています。

```html
<div class="greybox">
  Lorem ipsum
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center; 
}
```




```dart

var container = Container( // grey box
  child:  Center(
    child:  Text(
      "Lorem ipsum",
      style: bold24Roboto,
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 8.49.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/26f88097-0473-a5a9-9f00-108c24990804.png)


### Containerの幅を設定する

`Container` ウィジェットの幅を指定するには、その `width` プロパティを使用します。これは、Containerの幅を最大値まで調整する CSS の max-width プロパティとは異なり、固定の幅です。Flutter でこの効果を真似るには、Container の `constraints` プロパティを使用します。`minWidth` または `maxWidth` を持つ新しい `BoxConstraints` ウィジェットを作成します。

入れ子になったContainerの場合、親の幅が子の幅よりも小さい場合、子Containerは親に合わせてサイズを調整します。

```html

<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px; 
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  width: 100%;
  max-width: 240px; 
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red box
      child: Text(
        "Lorem ipsum",
        style: bold24Roboto,
      ),
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      padding: EdgeInsets.all(16),
      width: 240, //max-width is 240
    ),
  ),
  width: 320, 
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 8.50.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/014245c4-9ef7-a137-3147-e4976f15d7ad.png)


## 位置とサイズの操作

### 絶対位置の設定

デフォルトでは、ウィジェットは親に対して相対的に配置されます。

ウィジェットの絶対位置を x-y 座標で指定するには、`Stack` ウィジェットに入れ子になっている `Positioned` ウィジェットに入れ子にします。

```html

<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  position: relative; 
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  position: absolute;
  top: 24px;
  left: 24px; 
}
```

```dart
var container = Container( // grey box
  child: Stack(
    children: [
      Positioned( // red box
        child:  Container(
          child: Text(
            "Lorem ipsum",
            style: bold24Roboto,
          ),
          decoration: BoxDecoration(
            color: Colors.red[400],
          ),
          padding: EdgeInsets.all(16),
        ),
        left: 24,
        top: 24,
      ),
    ],
  ), 
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 8.55.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/0af54727-213e-0f22-1e91-eca9f4e5866d.png)

### 回転コンポーネント

ウィジェットを回転させるには、`Transform` ウィジェットに入れ子にします。`Transform` ウィジェットの `alignment` と `origin` プロパティを使用して、それぞれ相対語と絶対語で変換原点（支点）を指定します。

ウィジェットをZ軸で回転させる単純な2D回転については、新しいMatrix4 identityオブジェクトを作成し、その`rotateZ()`メソッドを使用して、ラジアン(度×π/180)を使用して回転係数を指定します。

```html

<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  transform: rotate(15deg); 
}
```

```dart

var container = Container( // gray box
  child: Center(
    child:  Transform(
      child:  Container( // red box
        child: Text(
          "Lorem ipsum",
          style: bold24Roboto,
          textAlign: TextAlign.center,
        ),
        decoration: BoxDecoration(
          color: Colors.red[400],
        ),
        padding: EdgeInsets.all(16),
      ),
      alignment: Alignment.center,
      transform: Matrix4.identity()
        ..rotateZ(15 * 3.1415927 / 180),
    ), 
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 8.59.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/ae385ecb-c914-c517-1ede-220d7d689b46.png)


### 拡大縮小コンポーネント

ウィジェットを拡大縮小するには、Transformウィジェットに入れ子にします。`Transform` ウィジェットの `alignment` と `origin` プロパティを使用して、それぞれ相対的または絶対的に変換原点（支点）を指定します。

x軸に沿った単純なスケーリング操作を行うには、新しい`Matrix4` identityオブジェクトを作成し、その `scale()`メソッドを使用してスケーリング係数を指定します。

親ウィジェットをスケーリングすると、その子ウィジェットもそれに応じてスケーリングされます。

```html
<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  transform: scale(1.5); 
}
```

```dart
var container = Container( // gray box
  child: Center(
    child:  Transform(
      child:  Container( // red box
        child: Text(
          "Lorem ipsum",
          style: bold24Roboto,
          textAlign: TextAlign.center,
        ),
        decoration: BoxDecoration(
          color: Colors.red[400],
        ),
        padding: EdgeInsets.all(16),
      ),
      alignment: Alignment.center,
      transform: Matrix4.identity()
        ..scale(1.5),
    ), 
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.09.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/5cc7fbc7-cb22-56e4-515e-d94f53846caf.png)

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

ウィジェットの背景に線形グラデーションを適用するには、 `Container` ウィジェットに入れ子にします。次に、`Container` ウィジェットの `decoration` プロパティを使用して `BoxDecoration` オブジェクトを作成し、`BoxDecoration` の `gradient` プロパティを使用して背景の塗りつぶしを変換します。

グラデーションの「角度」は、Alignment (x, y) の値に基づいています。

- x の最初と最後の値が等しい場合、グラデーションは垂直方向 (0° | 180°) となります。
- y の最初と最後の値が等しい場合、グラデーションは水平 (90° | 270°) です。

```html

<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  padding: 16px;
  color: #ffffff;
  background: linear-gradient(180deg, #ef5350, rgba(0, 0, 0, 0) 80%); 
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red box
      child: Text(
        "Lorem ipsum",
        style: bold24Roboto,
      ),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: const Alignment(0.0, -1.0),
          end: const Alignment(0.0, 0.6),
          colors: <Color>[
            const Color(0xffef5350),
            const Color(0x00ef5350)
          ],
        ),
      ), 
      padding: EdgeInsets.all(16),
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.14.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/bccee4dc-c3c0-f090-50cc-5956c974ba93.png)

```html
<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  padding: 16px;
  color: #ffffff;
  background: linear-gradient(90deg, #ef5350, rgba(0, 0, 0, 0) 80%); 
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red box
      child: Text(
        "Lorem ipsum",
        style: bold24Roboto,
      ),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: const Alignment(-1.0, 0.0),
          end: const Alignment(0.6, 0.0),
          colors: <Color>[
            const Color(0xffef5350),
            const Color(0x00ef5350)
          ],
        ),
      ), 
      padding: EdgeInsets.all(16),
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.16.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/2af72af0-f63c-fb87-f5b9-38c9b22e642f.png)

### 角を丸くする

矩形の角を丸めるには、`BoxDecoration` オブジェクトの `borderRadius` プロパティを使用します。各角を丸めるための半径を指定する `BorderRadius` オブジェクトを新規に作成します。

```html
<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* gray 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  border-radius: 8px; 
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red circle
      child: Text(
        "Lorem ipsum",
        style: bold24Roboto,
      ),
      decoration: BoxDecoration(
        color: Colors.red[400],
        borderRadius: BorderRadius.all(
          const Radius.circular(8),
        ), 
      ),
      padding: EdgeInsets.all(16),
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.41.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/0d2d1006-d4db-6a49-232b-cbea1780cd66.png)

### ボックスシャドウの追加

Flutterでは、それぞれのプロパティと値を個別に指定します。`BoxDecoration` の `boxShadow` プロパティを使って `BoxShadow` ウィジェットのリストを作成します。1つまたは複数の`BoxShadow` ウィジェットを定義することができ、それらを積み重ねて影の深さや色などをカスタマイズすることができます。

```html
<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.8),
              0 6px 20px rgba(0, 0, 0, 0.5);
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red box
      child: Text(
        "Lorem ipsum",
        style: bold24Roboto,
      ),
      decoration: BoxDecoration(
        color: Colors.red[400],
        boxShadow: [
          BoxShadow (
            color: const Color(0xcc000000),
            offset: Offset(0, 2),
            blurRadius: 4,
          ),
          BoxShadow (
            color: const Color(0x80000000),
            offset: Offset(0, 6),
            blurRadius: 20,
          ),
        ], 
      ),
      padding: EdgeInsets.all(16),
    ),
  ),
  width: 320,
  height: 240,
  decoration: BoxDecoration(
    color: Colors.grey[300],
  ),
  margin: EdgeInsets.only(bottom: 16),
);
```

![スクリーンショット 2020-08-03 9.44.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/94c0c0e5-096d-a561-53df-9ccea8017fa7.png)


### 円と楕円を作る

CSS で円を作るには四角形の四辺すべてに 50% の境界線を適用する必要があります。

Flutter は `BoxDecoration` の `borderRadius` プロパティでもサポートされていますが、円と楕円を作るために `BoxShape enum` で `shape` プロパティを提供しています。

```html
<div class="greybox">
  <div class="redcircle">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* gray 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redcircle {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  text-align: center;
  width: 160px;
  height: 160px;
  border-radius: 50%; 
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red circle
      child: Text(
        "Lorem ipsum",
        style: bold24Roboto,
        textAlign: TextAlign.center, 
      ),
      decoration: BoxDecoration(
        color: Colors.red[400],
        shape: BoxShape.circle, 
      ),
      padding: EdgeInsets.all(16),
      width: 160,
      height: 160, 
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.51.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/09b472dc-7ef1-f162-6086-ae3af79531c7.png)

## テキストの操作

### テキストの間隔を調整する

CSSでは、文字間隔プロパティと単語間隔プロパティにそれぞれ長さの値を与えることで、各文字や単語の間の空白の量を指定します。スペースの量は px、pt、cm、em などの単位で指定できます。

Flutter では、`Text` ウィジェットの `TextStyle` 子の `letterSpacing` と `wordSpacing` プロパティに、論理ピクセル（負の値も可）で空白を指定します。

```html

<div class="greybox">
  <div class="redbox">
    Lorem ipsum
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  letter-spacing: 4px; 
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red box
      child: Text(
        "Lorem ipsum",
        style: TextStyle(
          color: Colors.white,
          fontSize: 24,
          fontWeight: FontWeight.w900,
          letterSpacing: 4, 
        ),
      ),
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      padding: EdgeInsets.all(16),
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.53.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/ff8a271c-0310-b91c-10e3-bcbab691c1cf.png)

### インラインの書式変更を行う

テキストウィジェットは、いくつかのフォーマット特性を持つテキストを表示することができます。複数のスタイルを使用するテキスト (この例では、強調された単一の単語) を表示するには、代わりにリッチテキストウィジェットを使用します。その `text` プロパティは、個別にスタイルを設定できる 1 つ以上の `TextSpan` ウィジェットを指定することができます。

次の例では、"Lorem"はデフォルト（継承）のテキストスタイリングを持つ`TextSpan`ウィジェット内にあり、"ipsum "はカスタムスタイリングを持つ別の`TextSpan内`にあります。

```html

<div class="greybox">
  <div class="redbox">
    Lorem <em>ipsum</em>
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
}
 .redbox em {
  font: 300 48px Roboto;
  font-style: italic;
} 
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red box
      child:  RichText(
        text: TextSpan(
          style: bold24Roboto,
          children: <TextSpan>[
            TextSpan(text: "Lorem "),
            TextSpan(
              text: "ipsum",
              style: TextStyle(
                fontWeight: FontWeight.w300,
                fontStyle: FontStyle.italic,
                fontSize: 48,
              ),
            ),
          ],
        ),
      ), 
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      padding: EdgeInsets.all(16),
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.55.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/134bcce4-559c-611e-8b40-8be3144cf34e.png)

### テキストの抜粋を作成する

抜粋は、段落内のテキストの最初の行を表示し、オーバーフローしたテキストを処理します。HTML/CSSでは、抜粋は1行以下にすることができます。複数行の後に切り詰めるには、JavaScript のコードが必要です。

Flutter では、テキストウィジェットの `maxLines` プロパティを使用して、抜粋に含める行数を指定し、オーバーフローテキストを処理するために `overflow` プロパティを使用します。

```html
<div class="greybox">
  <div class="redbox">
    Lorem ipsum dolor sit amet, consec etur
  </div>
</div>

.greybox {
  background-color: #e0e0e0; /* grey 300 */
  width: 320px;
  height: 240px;
  font: 900 24px Roboto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.redbox {
  background-color: #ef5350; /* red 400 */
  padding: 16px;
  color: #ffffff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap; 
}
```

```dart
var container = Container( // grey box
  child: Center(
    child: Container( // red box
      child: Text(
        "Lorem ipsum dolor sit amet, consec etur",
        style: bold24Roboto,
        overflow: TextOverflow.ellipsis,
        maxLines: 1, 
      ),
      decoration: BoxDecoration(
        color: Colors.red[400],
      ),
      padding: EdgeInsets.all(16),
    ),
  ),
  width: 320,
  height: 240,
  color: Colors.grey[300],
);
```

![スクリーンショット 2020-08-03 9.56.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/6c144a95-bcbb-33c8-e35b-d5255c24c174.png)

# 感想
learn moreのコンテンツ内にあることもあり、結構読み飛ばしてしまう方が多いんじゃないかという気がしますが個人的には**必読**だと感じました。
今回ので理解がさらに深まった実感があります！✨

次回は[Introduction to widget](https://flutter.dev/docs/development/ui/widgets-intro)でウィジェットについて読んで行きたいと思います！