💡

【Flutter】ScaffoldのAppBarにPaddingを適用する方法

2024/03/02に公開

はじめに

Scaffoldで使用するAppBarウィジェットにはpaddingプロパティがないため直接パディングを適用することができません。
leadingやactionsにPaddingウィジェットを使用する方法もありますが、より簡単な方法を調べてみました。

問題点

例えばAppBarのleadingにアイコンとテキストを表示したい場合、leadingにRowウィジェットを使用することで実現できますが、その場合leadingが端により過ぎてしまいます(actionsも同様)。

Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        leading: const Row(
          children: [
            Expanded(child: Icon(Icons.arrow_back)),
            Text('Back'),
          ],
        ),
        title: Text('Flutter Demo Home Page'),
        actions: const [Icon(Icons.menu)],
      ),
...

そこでAppBarの左右にパディングを追加したいのですが、AppBar自体にはパディングを追加するためのプロパティが存在しません。leadingにPaddingウィジェットを使用することはできますが、アイコンとテキストが重なってしまい実現したい表示にはなりませんでした。

Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        // leadingにPaddingを適用
+       leading: const Padding(
+         padding: EdgeInsets.only(left: 8.0),
          child: Row(
            children: [
              Expanded(child: Icon(Icons.arrow_back)),
              Text('Back'),
            ],
          ),
        ),
        title: Text('Flutter Demo Home Page'),
        actions: const [Icon(Icons.menu)],
      ),
...

解決方法

ScaffoldのappBarプロパティにはAppBarクラスではなくPreferredSizeWidgetクラスを指定するようになっています[1]
実際にAppBarウィジェットの実装を確認するとPreferredSizeWidgetをimplementsしていることが分かります。

app_bar.dart
class AppBar extends StatefulWidget implements PreferredSizeWidget {
  /// Creates a Material Design app bar.
  ///
  /// If [elevation] is specified, it must be non-negative.
  ///
  /// Typically used in the [Scaffold.appBar] property.
...

そこでAppBarと同様にPreferredSizedWidgetを実装しているPreferredSizeウィジェットを使用します。
PreferredSizeウィジェットはchildとして任意のWidgetを持てるため、PaddingウィジェットでラップしたAppBarウィジェットを使用することでAppBar全体にパディングを適用できます。

PreferredSizeウィジェットには引数としてpreferredSizeを指定する必要があります。
これは親ウィジェットに対し、自身に制約がない場合の推奨サイズを伝えるためのものです。
Flutterに定義されている定数(kToolbarHeight)を使用すれば一般的なAppBarのサイズにすることができます。

下記のコード例ではPreferredSizeのchildにPaddingを追加し、PaddingのchildにAppBarを指定することでAppBar全体に対しパディングを適用することができました。

 Scaffold(
+      appBar: PreferredSize(
+       preferredSize: const Size.fromHeight(kToolbarHeight),
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20.0),
          child: AppBar(
            automaticallyImplyLeading: false,
            leading: const Row(
              children: [
                Expanded(child: Icon(Icons.arrow_back)),
                Text('Back'),
              ],
            ),
            title: Text('Flutter Demo Home Page'),
            actions: const [Icon(Icons.menu)],
          ),
        ),
      ),
...

参考

https://stackoverflow.com/questions/76789221/how-to-add-padding-to-the-leading-and-action-icons-on-the-appbar

脚注
  1. https://api.flutter.dev/flutter/material/Scaffold-class.html#instance-properties ↩︎

Discussion