Widget (Flutter Roadmap Widgets)

## はじめに
Flutterを網羅的に学習するにあたって[Roadmap](https://roadmap.sh/flutter)を使って学習を進めることにしました。

この記事では、Flutter初学者やこれからFlutterを学習し始める方に向けて、**Widgets**についてまとめています。

RoadmapはFlutterだけでなく、他の言語やスキルのロードマップも提供されており、何から学習して良いか分からないと悩んでいる方にとって有用なサイトになっています。
ぜひ[Roadmap](https://roadmap.sh/)を利用して学習してみてください。

## Roadmapとは

簡潔に言えば、Roadmap.shは学習者にとっての**ガイドブック**であり、**学習の方向性を提供する学習ロードマップサイト**です。

初心者から上級者まで、ステップバイステップでスキルを習得するための情報が提供されています。

学習の進め方が分かりやすく示されているだけでなく、個々の項目に参考資料やリソースへのリンクも提供されているので、学習者は目標を設定し、自分自身のペースで学習を進めることができます。

## Flutter IDE
FlutterロードマップWidgetsでは以下の21のサイトが紹介されています。興味のある方はぜひお読みください。

- Introduction to widgets: https://docs.flutter.dev/ui
- Widget catalog: https://docs.flutter.dev/ui/widgets
- Flutter Widgets Explained: https://www.youtube.com/watch?v=FU2Eeizo95o
- Official flutter responsive widget: https://docs.flutter.dev/ui/layout/responsive/adaptive-responsive
- Creating responsive and adaptive apps: https://docs.flutter.dev/ui/layout/responsive/adaptive-responsive
- InheritedWidget Official Guide: https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
- StatelessWidget class: https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html
- Flutter – Stateful vs Stateless Widgets: https://www.geeksforgeeks.org/flutter-stateful-vs-stateless-widgets/
- How to Create Stateless Widgets: https://medium.com/flutter/how-to-create-stateless-widgets-6f33931d859
- StatefulWidget class: https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html
- Flutter – Stateful vs Stateless Widgets: https://www.geeksforgeeks.org/flutter-stateful-vs-stateless-widgets/
- Flutter Tutorial - Stateful Widgets: https://www.youtube.com/watch?v=p5dkB3Mrxdo
- Styling widgets in Flutter: https://docs.flutter.dev/ui/widgets/styling
- Style Your Flutter Widgets: https://www.youtube.com/watch?v=kcq8AbVyMbk
- Material Components widgets: https://docs.flutter.dev/ui/widgets/material
- Flutter – Material Design: https://www.geeksforgeeks.org/flutter-material-design/
- Widget catalog in Flutter: https://docs.flutter.dev/ui/widgets
- Material Designs Guidlines: https://docs.flutter.dev/ui/widgets
- Cupertino (iOS-style) widgets: https://docs.flutter.dev/ui/widgets/cupertino
- Flutter Cupertino Tutorial: https://blog.logrocket.com/flutter-cupertino-tutorial-build-ios-apps-native/
- Flutter Cupertino Widgets: https://www.youtube.com/watch?v=L-TY_5NZ7z4



## Widgetとは
Widgetは、アプリのビューを構築するための要素です。画面上に表示されるコンポーネント[^1]、レイアウト、スタイルなどを表現します。Flutterでは、Widgetを組み合わせることによって、複雑なUIを作成することができます。
それぞれのWidget毎にプロパティ[^2]が予め用意されており、色を変えたり、大きさを調整したりなどはすべてWidgetが持つプロパティに設定していきます。

## 基本 Widget
### Text
テキストを表示するための基本的なウィジェットです。

- **Textコンテンツ** 
文字列を表示するためにtextプロパティにテキストコンテンツを指定します。

```dart
Text("Flutter");
```
- **Textスタイル**
テキストのスタイル（フォント、サイズ、色など）をカスタマイズするために、styleプロパティを使用します。

```dart
Text(
  "カスタムテキストスタイル",
  style: TextStyle(
    fontSize: 20.0,
    fontWeight: FontWeight.bold,
    color: Colors.blue,
  ),
);
```

- **Textの配置** 
テキストウィジェットのデフォルトの配置は左寄せですが、textAlignプロパティを使用してテキストの配置を調整できます。
```dart
Text(
  "中央揃えテキスト",
  textAlign: TextAlign.center,
);
```

- **Textの改行**
デフォルトでは、長いテキストは自動的に改行されます。`\n`を使用して手動で改行を挿入することもできます。

```dart
Text(
  "1行目\n2行目\n3行目",
);
``` 

- **Textの装飾**
decorationプロパティを使用して、テキストに下線や取り消し線などの装飾を追加できます。また、decorationColorやdecorationStyleを使用して、それらの装飾の色やスタイルをカスタマイズすることもできます。

```dart
Text(
  "下線付きテキスト",
  style: TextStyle(
    decoration: TextDecoration.underline,
    decorationColor: Colors.red,
    decorationStyle: TextDecorationStyle.dotted,
  ),
);
```

- **フォントのカスタマイズ**
fontFamilyプロパティを使用して、特定のフォントファミリーを指定できます。

```dart
Text(
  "カスタムフォント",
  style: TextStyle(
    fontFamily: "MyCustomFont",
  ),
);
```

### Image
画像を表示するために使用されるウィジェットです。アプリケーション内のローカル画像や、ネットワークからのリモート画像を表示するために利用できます。

- **ローカル画像の表示**
ローカルに保存された画像を表示する場合、プロジェクト内のassetsフォルダなどから画像を読み込みます。AssetImageを使用して、画像を指定します。

```dart
Image(
  image: AssetImage('assets/images/my_image.png'),
)
```

また、画像を表示するにはpubspec.yamlファイルでアセットを指定する必要があります。

- **ネットワークからの画像の表示**
ネットワーク上の画像を表示する場合、NetworkImageを使用します。URLを指定して画像を読み込みます。


```dart
Image(
  image: NetworkImage('https://example.com/my_image.jpg'),
)
```

- **画像のサイズ変更**
widthおよびheightプロパティを使用して、画像のサイズを変更できます。

```dart
Image(
  image: AssetImage('assets/images/my_image.png'),
  width: 200.0,
  height: 150.0,
)
```

- **フィットモード**
fitプロパティを使用して、画像のフィットモードを設定できます。例えば、BoxFit.coverは画像をアスペクト比[^3]を保持したまま最大まで表示します。

```dart
Image(
  image: AssetImage('assets/images/my_image.png'),
  width: 200.0,
  height: 150.0,
  fit: BoxFit.cover,
)
```

- **エラープレースホルダー**
errorBuilderプロパティを使用して、画像の読み込みに失敗した場合に表示するカスタムのウィジェットを指定できます。これにより、エラー処理をカスタマイズできます。

```dart
Image(
  image: NetworkImage('https://example.com/my_image.jpg'),
  errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
    return Text('画像を読み込めませんでした');
  },
)
```

### Button
ユーザーがアプリケーション内でアクションを実行する際に使用するウィジェットです。ボタンをタップすることで、特定の動作や処理がトリガーされます。

`onPressed`プロパティを使用してボタンが押されたときに実行されるコールバック関数を指定します。また、`child`プロパティを使用してボタン内に表示されるコンテンツ（テキストまたはアイコン）を指定します。

ボタンウィジェットを選択する際には、アプリケーションのUIやUXに合わせて適切なタイプを選択することが重要です。

- **ElevatedButton**
標準的な浮き上がったボタンを表現するためのウィジェットです。通常は、重要なアクションや主要な操作を示すために使用されます。

```dart
ElevatedButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  child: Text('Elevated Button'),
)
```

- **TextButton**
テキストスタイルのボタンを表現するためのウィジェットです。通常は、補助的なアクションやリンクを示すために使用されます。

```dart
TextButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  child: Text('Text Button'),
)
```

- **OutlinedButton**
ボタンの外側にアウトラインを持つウィジェットです。通常は、中程度のアクションを示すために使用されます。

```dart
OutlinedButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  child: Text('Outlined Button'),
)
```

- **IconButton**
アイコンを含むボタンを表現するためのウィジェットです。通常は、アイコンをタップしてアクションをトリガーするために使用されます。

```dart
IconButton(
  onPressed: () {
    // ボタンが押されたときの処理
  },
  icon: Icon(Icons.star),
)
```

### Container
他のウィジェットを包むコンテナやレイアウトの要素として使用されます。

**Containerの基本プロパティ**
|プロパティ|内容|
|---|---|
|child|単一のWidgetを作成|
|color|色の指定|
|alignment|child Widgetの位置を指定|
|height/width|高さ/幅の指定|
|margin|外側の余白を指定|
|padding|内側の余白を指定|
|decoration|外観をカスタマイズ|

```dart
Container(
      width: 200.0,
      height: 150.0,
      alignment: Alignment.center,
      margin: EdgeInsets.all(20.0),
      padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
      decoration: BoxDecoration(
        color: Colors.blue,
        border: Border.all(color: Colors.black, width: 2.0),
        borderRadius: BorderRadius.circular(10.0),
        boxShadow: [
          BoxShadow(
            color: Colors.grey,
            blurRadius: 5.0,
          ),
        ],
      ),
      child: Text(
        'Container',
        style: TextStyle(
          fontSize: 18.0,
          color: Colors.white,
        ),
      ),
    );
```

### Card
カードを表示するために使用されるウィジェットです。通常、情報をコンパクトに表示し、影や角丸などのスタイルを持つ要素として利用されます。

**Cardの基本プロパティ**
|プロパティ|説明|
|-----|-----|
|child|カード内に表示するコンテンツを指定|
|elevation|カードの影の深さを設定|
|shape|カードの形状をカスタマイズ|
|margin|カードの周りの余白を設定|
|color|カードの背景色を指定|

- **child**
Card内に表示するコンテンツを指定します。Text、Imageなどのウィジェットを含めることが多いですが、他のウィジェットも含めることができます。

```dart
Card(
  child: Column(
    children: <Widget>[
      Text('カードのタイトル'),
      Text('カードの内容'),
    ],
  ),
)
```

- **elevation**
カードの影の深さを設定します。値を大きくするほど、カードが浮き上がって見えます。デフォルト値は2.0です。

```dart
Card(
  elevation: 5.0,
  child: /* ... */,
)
```

- **shape**
カードの形状をカスタマイズできます。RoundedRectangleBorderやBeveledRectangleBorderを使用して、角丸や斜めの角を持つカードを作成します。

```dart
Card(
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(15.0),
  ),
  child: /* ... */,
)
```

- **margin**
カードの周りの余白を設定します。他の要素との間にスペースを追加するために使用されます。

```dart
Card(
  margin: EdgeInsets.all(10.0),
  child: /* ... */,
)
```

- **color**
カードの背景色を指定できます。通常、カードに色を設定することはありませんが、必要に応じて使用できます。

```dart
Card(
  color: Colors.blue,
  child: /* ... */,
)
```

### Column / Row
画面上のウィジェットの配置と整列を制御するために使用されます。

#### Columnウィジェット
子要素を垂直に配置するためのウィジェットです。縦に並ぶウィジェットのグループを作成するのに使用されます。childrenプロパティにColumn内に配置するウィジェットをリストで指定します。

```dart
Column(
  children: <Widget>[
    Text('項目1'),
    Text('項目2'),
    Text('項目3'),
  ],
)
```
子要素が**上から下に**順番に配置され、親要素の幅に合わせて伸縮します。

#### Rowウィジェット
子要素を水平に配置するためのウィジェットです。横に並ぶウィジェットのグループを作成するのに使用されます。childrenプロパティにRow内に配置するウィジェットをリストで指定します。

```dart
Row(
  children: <Widget>[
    Text('アイコン'),
    Text('テキスト'),
  ],
)
```

子要素が**左から右に**順番に配置され、親要素の高さに合わせて伸縮します。

**ColumnとRowウィジェットを使用したサンプルコード**

```dart
Column(
  children: <Widget>[
    Text('タイトル'),
    Text('サブタイトル'),
    Row(
      children: <Widget>[
        Icon(Icons.star),
        Text('5.0'),
      ],
    ),
  ],
)
```

### ListView

スクロール可能なリストを作成するためのウィジェットです。大量のアイテムをスクロール可能なリストとして表示することができます。

**ListViewの基本プロパティ**

|プロパティ|説明|
|---|---|
|children|ListView内に配置する子要素のリストを指定|
|scrollDirection|ListViewのスクロール方向を設定|
|itemBuilder|動的なリストを生成する|
|itemCount|ListView.builderを使用する場合、生成するアイテムの総数を指定|
|physics|スクロールの挙動を制御する|

- **children**
childrenプロパティは、ListView内に配置する子要素（ウィジェット）のリストを指定します。これらの子要素は通常、リスト内に表示される個々のアイテムです。

```dart
ListView(
  children: <Widget>[
    ListTile(title: Text('アイテム1')),
    ListTile(title: Text('アイテム2')),
    // 他のアイテム...
  ],
)
```

- **scrollDirection**
ListViewのスクロール方向を設定します。デフォルトでは垂直方向（Axis.vertical）ですが、水平方向にスクロールしたい場合はAxis.horizontalを使用します。

```dart
ListView(
  scrollDirection: Axis.horizontal,
  children: <Widget>[
    ListTile(title: Text('アイテム1')),
    ListTile(title: Text('アイテム2')),
    // 水平に並ぶアイテム...
  ],
)
```

- **itemBuilder**
動的なリストを生成する場合にカスタムアイテムを生成する関数を指定できます。`ListView.builder`と組み合わせて使用されます。

```dart
ListView.builder(
  itemCount: items.length,
  itemBuilder: (BuildContext context, int index) {
    return ListTile(title: Text(items[index]));
  },
)
```

- **itemCount**
ListView.builderを使用する場合に生成するアイテムの総数を指定します。

```dart
ListView.builder(
  itemCount: items.length,
  itemBuilder: (BuildContext context, int index) {
    return ListTile(title: Text(items[index]));
  },
)
```

`itemBuilder`と`itemCount`に関してわかりやすい記事があったので、是非読んでみてください。

https://note.com/hatchoutschool/n/n23814a97d2eb

https://yakiimosan.com/flutter-listviewbuilder/

- **physics**
スクロールの挙動を制御するために使用されます。例えば、スクロールの動きやバウンスなどをカスタマイズできます。

```dart
ListView(
  physics: BouncingScrollPhysics(),
  children: <Widget>[
    // アイテム...
  ],
)
```

https://www.choge-blog.com/programming/flutterlistview-scrollphyscics/


### AppBar
アプリケーションの上部に表示されるアプリケーションバーを作成するためのウィジェットです。アプリケーションのタイトル、アイコン、アクションボタン、その他メニューアイテムを配置することが一般的です。

**AppBarの基本プロパティ**

|プロパティ|説明|
|---|---|
|title|アプリケーションバーに表示されるタイトルを設定|
|actions|アプリケーションバーに表示されるアイコンボタンやメニューアイテムのリストを指定|
|leading|アプリケーションバーの左端に表示される要素を指定|
|backgroundColor|アプリケーションバーの背景色を設定|
|elevation|アプリケーションバーの影の深さを設定|

- **title**
アプリケーションバーに表示されるタイトルを設定します。

```dart
AppBar(
  title: Text('My App'),
)
```

- **actions**
アプリケーションバーに表示されるアクションボタン（アイコンボタンやメニューアイテム）のリストを指定します。

```dart
AppBar(
  actions: <Widget>[
    IconButton(
      icon: Icon(Icons.search),
      onPressed: () {
        // 検索アクションの処理
      },
    ),
    IconButton(
      icon: Icon(Icons.settings),
      onPressed: () {
        // 設定アクションの処理
      },
    ),
  ],
)
```

- **leading**
アプリケーションバーの左端に表示される要素を指定します。ハンバーガーメニューアイコンなどを配置する際に多く使用されます。

```dart
AppBar(
  leading: IconButton(
    icon: Icon(Icons.menu),
    onPressed: () {
      // メニューアクションの処理
    },
  ),
)
```

- **backgroundColor**
アプリケーションバーの背景色を設定します。

```dart
AppBar(
  backgroundColor: Colors.blue,
)
```

- **elevation**
アプリケーションバーの影の深さを設定します。値を大きくするほど、アプリケーションバーが浮き上がって見えます。

```dart
AppBar(
  elevation: 4.0,
)
```

https://zenn.dev/sugitlab/articles/e68b2fce02e50f

### Scaffold
Scaffoldは「足場」という意味になりますが、アプリ画面でよく使われるメニュー表示方法を含めて画面全体を管理するウィジェットです。

**Scaffoldの基本プロパティ**

|プロパティ|説明|
|---|---|
|appBar|AppBarウィジェットを指定|
|body|画面の本文コンテンツを指定|
|drawer|ハンバーガーメニューを指定|
|floatingActionButton|画面のフローティングアクションボタンを指定|
|floatingActionButtonLocation|フローティングアクションボタンの位置を設定|
|persistentFooterButtons|画面の下部に固定されるボタンのリストを指定|
|backgroundColor|Scaffoldの背景色を設定|
|resizeToAvoidBottomInset|キーボードが表示されたときにコンテンツをスクロールするかどうかを設定|
|extendBody|bodyコンテンツを画面の下部まで拡張するかどうかを制御|
|extendBodyBehindAppBar|appBarの下にコンテンツを表示するかどうかを制御|

- **appBar**
AppBarウィジェットを指定します。アプリケーションの上部に表示され、通常はタイトルやアクションボタンを含みます。

```dart
Scaffold(
  appBar: AppBar(
    title: Text('My App'),
  ),
  // 他のウィジェットを含む
)
```

- **body**
画面の本文コンテンツを指定します。ページの中身やリストビュー、フォームなどを含みます。

```dart
Scaffold(
  body: Center(
    child: Text('Hello, World!'),
  ),
  // 他のウィジェットを含む
)
```

- **drawer**
ハンバーガーメニューを指定します。通常、サイドバーのナビゲーションメニューや設定メニューを表示するのに使用されます。

```dart
Scaffold(
  appBar: AppBar(
    title: Text('My App'),
  ),
  drawer: Drawer(
    // ハンバーガーメニューの内容を指定
  ),
  // 他のウィジェットを含む
)
```

- **floatingActionButton**
画面のフローティングアクションボタンを指定します。主要なアクションや追加操作を実行するために使用されます。

```dart
Scaffold(
  appBar: AppBar(
    title: Text('My App'),
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      // フローティングアクションの処理
    },
    child: Icon(Icons.add),
  ),
  // 他のウィジェットを含む
)
```

- **floatingActionButtonLocation**
フローティングアクションボタンの配置を制御します。設定には次のようなものがあります。

    - FloatingActionButtonLocation.endFloat: デフォルト設定。画面の右下に配置されます。
    - FloatingActionButtonLocation.centerFloat: 画面の中央下に配置されます。
    - FloatingActionButtonLocation.miniStartTop: 画面の左上に小さなサイズで配置されます。
```dart
Scaffold(
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      // フローティングアクションの処理
    },
    child: Icon(Icons.add),
  ),
  floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
  // 他のウィジェットを含む
)
```

- **persistentFooterButtons**
画面の下部に固定されるボタン(コンテンツとは独立して表示されるアクションボタン)を指定します。

```dart
Scaffold(
  persistentFooterButtons: <Widget>[
    ElevatedButton(
      onPressed: () {
        // ボタンの処理
      },
      child: Text('ボタン1'),
    ),
    ElevatedButton(
      onPressed: () {
        // ボタンの処理
      },
      child: Text('ボタン2'),
    ),
  ],
  // 他のウィジェットを含む
)
```

- **backgroundColor**
Scaffoldの背景色を設定します。通常はColorsクラスの色を指定しますが、任意のColorオブジェクトを使用することもできます。

```dart
Scaffold(
  backgroundColor: Colors.grey[200],
  // 他のウィジェットを含む
)
```

 - **resizeToAvoidBottomInset**
キーボードが表示された際の画面のリサイズを制御します。trueに設定すると、キーボードが表示されたときにコンテンツが自動的にスクロールして隠れないようになります。

```dart
Scaffold(
  resizeToAvoidBottomInset: false, // スクロールなし
  // 他のウィジェットを含む
)
```

https://qiita.com/mu-suke08/items/40e8f203f78f96a47bda

- **extendBody**
bodyコンテンツを画面の下部まで拡張するかどうかを制御します。trueに設定すると、背景色やデザインがbodyまで広がり、下部ナビゲーションバーを含めた全体の高さになります。

```dart
Scaffold(
  extendBody: true,
  // 他のウィジェットを含む
)
```

https://www.choge-blog.com/programming/flutterbottomnavigationbar-backscreen/

- **extendBodyBehindAppBar**
appBarの下にコンテンツを表示するかどうかを制御します。trueに設定すると、appBarの下にbodyコンテンツが表示され、appBarの背後に配置されます。

```dart
Scaffold(
  extendBodyBehindAppBar: true,
  // 他のウィジェットを含む
)
```

https://www.choge-blog.com/programming/flutterappbar-in-body/

**Scaffoldサンプルコード**
```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyScaffoldApp(),
    );
  }
}

class MyScaffoldApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.search),
            onPressed: () {
              // 検索アクションの処理
            },
          ),
        ],
      ),
      body: Center(
        child: Text('Hello, World!'),
      ),
      drawer: Drawer(
        child: ListView(
          children: <Widget>[
            ListTile(
              title: Text('メニュー1'),
              onTap: () {
                // メニュー1の処理
              },
            ),
            ListTile(
              title: Text('メニュー2'),
              onTap: () {
                // メニュー2の処理
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // フローティングアクションの処理
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
      persistentFooterButtons: <Widget>[
        ElevatedButton(
          onPressed: () {
            // ボタン1の処理
          },
          child: Text('ボタン1'),
        ),
        ElevatedButton(
          onPressed: () {
            // ボタン2の処理
          },
          child: Text('ボタン2'),
        ),
      ],
      backgroundColor: Colors.grey[200],
      resizeToAvoidBottomInset: true,
      extendBody: true,
      extendBodyBehindAppBar: false,
    );
  }
}
```

### InheritedWidget
ウィジェットツリー内でデータを共有するための仕組みです。親ウィジェットから子ウィジェットにデータを渡す際に使用します。データをInheritedWidgetに持たせることで、依存関係がInheritedWidgetの下にあるWidgetならどこからでもデータを参照できるようになります。
`Providerパッケージ`や`Riverpodパッケージ`の普及によりInheritedWidgetを使用する機会はほとんど無くなってきていますが、InheritedWidgetの仕組みを理解することでProviderパッケージやRiverpodパッケージへの理解を深めることができます。

```dart: InheritedWidgetを使用したカウンタアプリ
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

// カウンターの状態を提供するカスタムInheritedWidget
class CounterProvider extends InheritedWidget {
  final int counter; // カウンターの値
  final Function() increment; // カウンターを増やす関数

  const CounterProvider({
    super.key,
    required this.counter, // 初期カウンターの値
    required this.increment, // カウンターを増やす関数
    required Widget child, // 子ウィジェット
  }) : super(child: child);

  // InheritedWidgetを使ってカウンターの状態を取得するためのメソッド
  static CounterProvider? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterProvider>();
  }

  @override
  bool updateShouldNotify(covariant InheritedWidget oldWidget) {
    return false; // このメソッドは更新通知の制御に使われますが、この例では常にfalseを返しています
  }
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: CounterApp(),
    );
  }
}

class CounterApp extends StatefulWidget {
  const CounterApp({super.key});

  @override
  CounterAppState createState() => CounterAppState();
}

class CounterAppState extends State<CounterApp> {
  int _counter = 0; // カウンターの初期値

  // カウンターを増やす関数
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return CounterProvider(
      counter: _counter, // カウンターの初期値を設定
      increment: _incrementCounter, // カウンターを増やす関数
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Counter App'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'Count:',
                style: TextStyle(fontSize: 20.0),
              ),
              Builder(
                builder: (context) {
                  final counterProvider = CounterProvider.of(context);
                  return Text(
                    '${counterProvider?.counter}', // カウンターの値を表示
                    style: const TextStyle(fontSize: 40.0),
                  );
                },
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}
```

https://blog.flutteruniv.com/flutter-inheritedwidget/

https://zenn.dev/naoya_maeda/articles/63c707ad8f36a2

### StatelessWidget
状態を持たないウィジェットです。一度作成されたらその内容や見た目が変更されないウィジェットになりますので、通常、静的なコンテンツを表示するために使用されます。ウィジェットツリー内での再構築の必要がないため、効率的に動作します。

**StatelessWidgetのサンプルコード**
```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hello Flutter Example',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Hello Flutter Example'),
        ),
        body: Center(
          // Stateless Widgetを呼び出す
          child: HelloFlutter(),
        ),
      ),
    );
  }
}

class HelloFlutter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      'Hello, Flutter!',
      style: TextStyle(fontSize: 24),
    );
  }
}
```

### StatefulWidget
状態を持つウィジェットです。状態（State）は、ウィジェットが再描画されるときに変更することができます。ユーザー入力や時間の経過に応じて画面の情報を変更する際などに使用されます。

`StatefulWidget`は**不変であるWidgetを継承**しているので、`StatefulWidget`自体は**不変**である必要があります。ではなぜ`StatefulWidget`が状態を持つウィジェットなのか?　その理由は`State`です。`State`に**可変の要素**を持たせています。
Flutter SDKは`StatefulWidget`を**何度も再作成する**ことができ、**それに対しStateは１度だけ作成**されます。そして、**再作成されたStatefulWidgetは既に作成されているStateを参照する**ことで、Widgetの再作成（画面の描画）を行うことができます。

**StatefulWidgetのサンプルコード**

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Counter App Example',
      home: CounterApp(),
    );
  }
}

class CounterApp extends StatefulWidget {
  @override
  _CounterAppState createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Counter Value:',
              style: TextStyle(fontSize: 20),
            ),
            Text(
              '$_counter',
              style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
```

https://tech-rise.net/why-stateful-widget-separates-two-classes/

### Material Widgets
Flutterのデザインライブラリである`Material Design`に基づいて設計されたウィジェットのセットです。Material Designは、Googleが提供するデザインガイドラインで、アプリケーションの外観と動作を構築するのに使用されます。

https://zenn.dev/tatsuyasusukida/scraps/d03480f133d114

https://docs.flutter.dev/ui/widgets/material

https://flutter.keicode.com/basics/index-material.php

#### 例
- **RaisedButton** 
タップすると反応するデザインで、ユーザーアクションを促します。

- **TextField**
ユーザーがテキストを入力できるウィジェットで、バリデーションやテキスト操作に対応します。
- **Card**
情報を整理して表示し、視覚的な階層を作成するのに使用されます。

- **AppBar**
アプリケーションの上部にタイトルやアクションボタンを表示し、ナビゲーションメニューを提供します。

- **ListView**
スクロール可能なリストを表示し、大量のデータを効果的に表示できます。

- **SnackBar**
一時的なメッセージや通知を表示するためのウィジェットです。

- **BottomNavigationBar**
アプリケーションの下部にナビゲーションメニューを提供し、異なる画面間を移動できます。

### Cupertino Widgets
iOSのデザインガイドラインに従ったFlutterのウィジェットの一部で、iOSアプリケーションを開発する際、iOSのネイティブな外観と動作を構築するために使用されます。

#### 例
- **CupertinoButton**
タップすると反応するデザインで、iOSアプリケーションに一般的に使用されます。

- **CupertinoTextField**
テキスト入力フィールド。iOSのテキスト入力フィールドの外観と動作を提供します。

- **CupertinoNavigationBar**
アプリケーションの上部にタイトルやアクションボタンを表示し、iOSアプリケーションに一般的に使用されます。

- **CupertinoAlertDialog**
メッセージやアクションボタンを含むアラートを表示します。iOSアプリケーションに一般的に使用されます。

- **CupertinoPicker**
ドロップダウンリストや選択ウィジェットとして使用され、iOSアプリケーションに一般的に使用されます。

https://zenn.dev/tatsuyasusukida/scraps/cb83c543cc3483

https://docs.flutter.dev/ui/widgets/cupertino

https://tech-rise.net/flutter-ios-style-cupertino-widgets/

## Responsive Widgetとは
Responsive Widgetとは異なる画面サイズやデバイスに対応したウィジェット（コンポーネント）のことです。Flutterにおいて、Responsive Widgetを作成するためには、以下のようなアプローチがあります。

### MediaQueryを使用する
MediaQueryクラスは、デバイスの画面サイズ、方向、ピクセル比率などの情報にアクセスするために使用されます。これを使用して、画面幅に基づいて異なるウィジェットを表示するなどの条件分岐を行うことができます。

```dart
final double screenWidth = MediaQuery.of(context).size.width;

if (screenWidth > 600) {
  // 大画面向けのウィジェットを表示
  return DesktopWidget();
} else {
  // スマートフォン向けのウィジェットを表示
  return MobileWidget();
}
```

https://yamochun-dev.cloud/dev/flutter/about-responsive-mediaquery/

### LayoutBuilderを使用する
LayoutBuilderウィジェットは、親ウィジェットのサイズに基づいて子ウィジェットを構築するのに使用されます。親ウィジェットのサイズに合わせて子ウィジェットの配置やサイズを動的に調整できるため、ウィンドウの幅に応じて列の数を調整する際などに使用します。

```dart
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      // 大画面向けの表示
      return Row(
        children: <Widget>[
          Expanded(child: Widget1()),
          Expanded(child: Widget2()),
        ],
      );
    } else {
      // スマートフォン向けの表示
      return Column(
        children: <Widget>[
          Widget1(),
          Widget2(),
        ],
      );
    }
  },
)
```

https://flutter.salon/widget/layoutbuilder/

### Responsiveパッケージを使用する
Flutterには、レスポンシブデザインを簡素化するためのパッケージが多数存在します。例えば、`responsive_framework`や`flutter_responsive`などのパッケージを使用すると、簡単にレスポンシブなレイアウトを作成できます。プロジェクトや使用感などご自身に合ったパッケージを選択してみてください。

https://pub.dev/packages/responsive_framework

https://pub.dev/packages/flutter_responsive

### FlexやExpandedを使用する
**Flexウィジェット**や**Expandedウィジェット**を活用することで、ウィジェットのサイズや配置を調整できます。これらのウィジェットを使用することで、利用可能なスペースを最大限に活用することができます。
FlexibleとExpandedの**主な違いは、サイズ調整の方法**にあります。Flexibleはウィジェットのサイズを柔軟に調整できるのに対して、Expandedは利用可能な空間をすべて埋めるようにウィジェットを拡張します。

https://flutter.salon/widget/flexible/

## 参考資料
https://zenn.dev/kboy/books/ca6a9c93fd23f3/viewer/0f62d6

https://www.flutter-study.dev/widgets/text-widget

https://terupro.net/flutter-widget-container/

https://codezine.jp/article/detail/13329

https://4qualia.co.jp/technology/solution_business/flutter/20230706103208.html

https://www.memory-lovers.blog/entry/2023/07/14/134219

https://qiita.com/1hour/items/c2e1d1c8eaf78a8d615c

[^1]: **コンポーネント**
単体では使用せず、他のプログラムから呼び出されたり連結されたりして使用されるプログラム部品のこと
[こちら](https://wa3.i-3-i.info/word12384.html)にわかりやすい記事があったので、是非読んでみてください。


[^2]: **プロパティ**
取り扱う対象（オブジェクト）の持つ設定や状態、属性などの情報のことです。
[こちら](https://wa3.i-3-i.info/word11066.html)にわかりやすい記事があったので、是非読んでみてください。

[^3]: **アスペクト比**
アスペクト比とは、画像や動画等の映像の縦横比のことを指します。一般的にワイド(16:9)とスタンダード(4:3)の2つが基本的なアスペクト比とされています。
https://gimo.jp/glossary/details/aspect_ratio.html