Flutterを使ってアプリ開発をしていると、UIをカスタマイズしたくなる瞬間が必ずやってきます。
特に、アプリの顔とも言えるAppBarは、デザインにおいて重要な役割を果たします。
そこで、私はReUsableAppBarという名前でカスタムAppBarウィジェットを作成することにしました。これはStatelessWidgetを継承し、再利用しようとしたらエラーが....
コード
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"),
);
}
}
遭遇した問題
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?」って何?と思い、調べてみました。
どうやら、これはウィジェットの高さに関係している重要なインターフェースのようです。
原因の解明
Scaffold内で宣言される際に、AppBarはフレームワークによって自動的に適切な高さが決定されます。これはAppBarがPreferredSizeWidgetインターフェースを実装しているためで、このインターフェースを通じてAppBarの高さ情報がFlutterに伝えられます。
しかし、私が作成したReUsableAppBarカスタムウィジェットでは、このPreferredSizeWidgetインターフェースを明示的に実装していませんでした。そのため、Flutterフレームワークはカスタムウィジェットの高さを自動的に判断できず、ScaffoldのappBarプロパティに割り当てようとした際に型の不一致エラーが発生してしまったのです。
[解決策1]AppBarウィジェットを返す静的メソッドを持つユーティリティクラス(例: UIConstants)を作成する
解決の鍵は、UIConstantsというユーティリティクラスを作成し、その中でAppBarウィジェットを返す静的メソッドを定義することでした。
このメソッドを通じてAppBarウィジェットを直接取得することで、AppBar自体が既にPreferredSizeWidgetを実装しており、そのpreferredSizeプロパティを通じて高さ情報を提供しているため、型の不一致の問題は解決されます。
class UIConstants {
static AppBar appBar() {
return AppBar(
title: Text("Reusable AppBar"),
);
}
}
この方法を用いることで、カスタムAppBarをScaffoldのappBarプロパティに問題なく割り当てることができました。
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に伝えることができます。
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で使用する場合、二つの方法を紹介しました。
-
StatelessWidgetを継承し、PreferredSizeWidgetを実装するカスタムAppBarを作成する方法 -
AppBarウィジェットを返す静的メソッドを持つユーティリティクラスを定義する方法
どちらの方法も、FlutterのPreferredSizeWidgetの要件を満たし、型の不一致エラーを回避することができます。