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
の要件を満たし、型の不一致エラーを回避することができます。