カスタムAppBarを作成して使おうとしたら、型の不一致エラーが発生したので調べてみた:The argument type 'ReUsableAppBar' can't be assigned to the parameter type 'PreferredSizeWidget?'.

Flutterを使ってアプリ開発をしていると、UIをカスタマイズしたくなる瞬間が必ずやってきます。
特に、アプリの顔とも言えるAppBarは、デザインにおいて重要な役割を果たします。
そこで、私は`ReUsableAppBar`という名前でカスタム`AppBar`ウィジェットを作成することにしました。これは`StatelessWidget`を継承し、再利用しようとしたらエラーが....

# コード
```dart:カスタムAppBar
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:x_clone/constants/assets_constants.dart';

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

  @override
  Widget build(BuildContext context) {
    return AppBar(
     title: Text("Reusable AppBar"),
    );
  }
}
```



# 遭遇した問題

```dart:問題のコード
class LoginView extends StatefulWidget {
  const LoginView({super.key});

  @override
  State<LoginView> createState() => _LoginViewState();
}

class _LoginViewState extends State<LoginView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: ReUsableAppBar(),
    );
  }
}

```

`AppBar`カスタムウィジェットをScaffoldに組み込んで実行したところ、予期せぬエラーが発生しました。
```
The argument type 'ReUsableAppBar' can't be assigned to the parameter type 'PreferredSizeWidget?'.
```

「PreferredSizeWidget?」って何？と思い、調べてみました。
どうやら、これはウィジェットの高さに関係している重要なインターフェースのようです。

# 原因の解明
:::note 
`Scaffold`内で宣言される際に、`AppBar`はフレームワークによって自動的に適切な高さが決定されます。これは`AppBar`が`PreferredSizeWidget`インターフェースを実装しているためで、このインターフェースを通じて`AppBar`の高さ情報がFlutterに伝えられます。
:::

しかし、私が作成した`ReUsableAppBar`カスタムウィジェットでは、この`PreferredSizeWidget`インターフェースを明示的に実装していませんでした。そのため、Flutterフレームワークはカスタムウィジェットの高さを自動的に判断できず、`Scaffold`の`appBar`プロパティに割り当てようとした際に型の不一致エラーが発生してしまったのです。

# [解決策1]AppBarウィジェットを返す静的メソッドを持つユーティリティクラス（例: UIConstants）を作成する
解決の鍵は、`UIConstants`というユーティリティクラスを作成し、その中でAppBarウィジェットを返す静的メソッドを定義することでした。
このメソッドを通じてAppBarウィジェットを直接取得することで、AppBar自体が既に`PreferredSizeWidget`を実装しており、その`preferredSize`プロパティを通じて高さ情報を提供しているため、型の不一致の問題は解決されます。
```dart
class UIConstants {
  static AppBar appBar() {
    return AppBar(
      title: Text("Reusable AppBar"),
    );
  }
}

```
この方法を用いることで、カスタム`AppBar`を`Scaffold`の`appBar`プロパティに問題なく割り当てることができました。

```dart:上手くいったコード
import 'package:flutter/material.dart';
import 'package:x_clone/constants/ui_constants.dart';

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

  @override
  State<LoginView> createState() => _LoginViewState();
}

class _LoginViewState extends State<LoginView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: UIConstants.appBar(),
    );
  }
}
```

# [解決策2]`StatelessWidget`を継承し、`PreferredSizeWidget`を実装するカスタム`AppBar`ウィジェットを作成する
この方法では、カスタムウィジェット内で`AppBar`を使用し、同時に`PreferredSizeWidget`インターフェースを実装して、`preferredSize`プロパティを提供します。これにより、ウィジェットの高さを明示的にFlutterに伝えることができます。


```dart
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
  const CustomAppBar({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: Text("カスタムAppBar"),
    );
  }

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight); // ここでAppBarの高さを指定
}
//preferredSizeプロパティは、AppBarの高さを指定するために使用されます。
//kToolbarHeightはFlutterが提供する標準のアプリバーの高さの定数
```
* カスタムAppBarクラスが`PreferredSizeWidget`インターフェースを実装するようにします。
  * 実装するためには、クラス宣言の一部として`PreferredSizeWidget`を追加し、必要な`preferredSize`プロパティをオーバーライドします。



# まとめ
カスタムAppBarウィジェットを`Scaffold`で使用する場合、二つの方法を紹介しました。


1. `StatelessWidget`を継承し、`PreferredSizeWidget`を実装するカスタムAppBarを作成する方法

2. AppBarウィジェットを返す静的メソッドを持つユーティリティクラスを定義する方法

どちらの方法も、Flutterの`PreferredSizeWidget`の要件を満たし、型の不一致エラーを回避することができます。