🍜

Flutter MediaQuery.removePaddingによってviewPaddingが0になる

に公開

Overlay Widgetを使ってWidgetツリーを飛び越えて表示した時に、viewPaddingの値が想定と違い混乱することがありました。これはMediaQuery.removePaddingが適用されたWidgetツリーの内側と外側で、viewPaddingの値が異なることが原因でした。
この記事では、MediaQuery.removePaddingの使い方と、viewPaddingの値が変わる理由を解説します。

MediaQuery.removePadding

MediaQuery.removePaddingメソッドは、指定したパディングを0に置き換えたMediaQueryDataを作成します。

これは、AppBarSafeAreaといったWidgetの内部で使われています。

AppBarは、removeBottom: trueによって、画面下のパディングが0に指定されています。

https://github.com/flutter/flutter/blob/a0b1b3253416b1f19e3f105b596eb6e4c5813ef4/packages/flutter/lib/src/material/app_bar.dart#L2099-L2103

SafeAreaは、パラメータで指定した位置のパディングが0に指定されていますね。

https://github.com/flutter/flutter/blob/a0b1b3253416b1f19e3f105b596eb6e4c5813ef4/packages/flutter/lib/src/widgets/safe_area.dart#L128-L135

SafeAreaのパディングを削除するパラメータはデフォルトでtrueです。
例えば、以下のコードだと画面の左・右・上のパディングが0になります。

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return SafeArea(top: false, child: Text('テスト'));
  }
}

MediaQuery.viewPaddingの値が変わる

removePaddingによってviewPaddingの値が変わることを見てみましょう。
以下はAppBarMediaQuery.removePaddingを順番に適用したコードです。

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: _ViewPaddingWidget()));
}

class _ViewPaddingWidget extends StatelessWidget {
  
  Widget build(BuildContext contextX) {
    return Scaffold(
      // removeTop: true,
      appBar: AppBar(title: Text('AppBar')),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // EdgeInsets.fromLTRB(left, top, right, bottom)
          Text('contextX: ${MediaQuery.viewPaddingOf(contextX)}'),
          Builder(
            builder:
                (contextY) => Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('contextY: ${MediaQuery.viewPaddingOf(contextY)}'),
                    MediaQuery.removePadding(
                      context: contextY,
                      removeBottom: true,
                      child: Builder(
                        builder:
                            (contextZ) => Text(
                              'contextZ: ${MediaQuery.viewPaddingOf(contextZ)}',
                            ),
                      ),
                    ),
                  ],
                ),
          ),
        ],
      ),
    );
  }
}

このコードを実行すると、contextX、contextY、contextZの順にパディングが無くなっていることが確認できます。

以下はiPhone Xsで実行した結果です。上下にviewPaddingが設定された後、上パディングがなくなり、下パディングがなくなっています。

まとめ

  • MediaQuery.removePaddingによって、MediaQuery.viewPaddingの値が変わる
  • MediaQuery.removePaddingは、AppBarSafeAreaの内部で使われている
  • MediaQuery.removePaddingは、指定したパディングを0に置き換えたMediaQueryDataを作成する

参考文献

https://api.flutter.dev/flutter/widgets/MediaQueryData/removePadding.html

https://qiita.com/zundaman/items/9f5c83132403fc973ea1

Discussion