Flutter: ステータスバーの高さ「padding.top」を取得したが、値がゼロになってしまう
結論:contextを引数で渡すか、起動時にpadding.topを取得しておく
2022/8/7 Flutter エラー・バグ日記
スマホ画面最上部の電池マークやWiFiマークのあるゾーン(ステータスバーと言うらしい)の高さを取得するため、
MediaQuery.of(context).padding.top
のプロパティにアクセスしたのだが、なぜか取得した値がゼロになる状況に陥った。
調べてみると、下記の情報があった。
若干、本件とは異なるケースの話だが、回答にある「contextのpaddingがゼロ」のウィジェットに対して実行しているから、というコメントで気がついた。
自分のコードでは、「Column」で並べたウィジェットのうち、一部のウィジェットを別クラス(Stateless Widget)に飛ばし、その別クラス内で、「padding.top」を取得しようとしていた。
最初の画面全体のビルドを担う「build」メソッドが持つ「context」は、画面上部の「padding」=「ステータスバーの高さ」を認識しているが、別クラスに飛んだ先のウィジェットのビルドを担う「build」メソッドが持つ「context」には、画面全体のpadding情報が無いため、ゼロになる、ということだと思われる。
確かに、画面全体のビルドを担う「build」メソッドが持つ「context」を、別クラスに引数として渡し、渡された「context」を使って「padding.top」にアクセスしたら、ステータスバーの値を取得できた。
画面横幅を取得する「MediaQuery.of(context).size.width」や、画面縦幅を取得する「MediaQuery.of(context).size.height」では、こういう問題は生じないのだが(contextを渡さずに、別クラスに飛んだ先で値を取得できる)、「padding.top」は事情が違うらしい。
上記のことを検証するため、下記サンプルコードを作成して確かめてみた。
「context」を引数として渡さないウィジェットでは、「padding.top」が取得できず、渡したウィジェットでは取得できていることが分かる。
// クラス名、メソッド名、プロパティ名(変数名)について、筆者が作成したもの(名前変更可のもの) // の名前の末尾には、大文字のオー「O」をつけています // ※ライブラリ(パッケージ)で予め決められているもの(名前の変更不可のもの)と、 // 自分で作成したもの(名前の変更可のもの)の区別をしやすくするため import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: "Test", theme: ThemeData.light(), home: SampleScreenO(), ); } } class SampleScreenO extends StatefulWidget { @override _SampleScreenOState createState() => _SampleScreenOState(); } class _SampleScreenOState extends State<SampleScreenO> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( height: 50, color: Colors.blue, child: Text("ステータスバーの高さ ${MediaQuery.of(context).padding.top}"), ), Container( height: 50, color: Colors.lightBlue, child: Text("画面の縦幅 ${MediaQuery.of(context).size.height}"), ), /// contextを引き継がないウィジェット TestWidgetO(), /// contextを引き継ぐウィジェット AnotherTestWidgetO(contextO: context), ], ), ); } } /// contextを引き継がないウィジェット class TestWidgetO extends StatelessWidget { const TestWidgetO({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( height: 50, color: Colors.green, child: Text("ステータスバーの高さ ${MediaQuery.of(context).padding.top}"), ), Container( height: 50, color: Colors.lightGreen, child: Text("画面の縦幅 ${MediaQuery.of(context).size.height}"), ), ], ); } } /// contextを引き継ぐウィジェット class AnotherTestWidgetO extends StatelessWidget { final BuildContext contextO; const AnotherTestWidgetO({ Key? key, required this.contextO, }) : super(key: key); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( height: 50, color: Colors.yellow, // 引き継いだ「contextO」を用いて「padding.top」にアクセス child: Text("ステータスバーの高さ ${MediaQuery.of(contextO).padding.top}"), ), Container( height: 50, color: Colors.limeAccent, child: Text("画面の縦幅 ${MediaQuery.of(context).size.height}"), ), ], ); } }
実用面では、「context」を渡していくのは面倒なので、アプリ起動時に「padding.top」にアクセスし、定数に代入しておくのが良さそうだと思った。
\一般的なエラー対処法をまとめた記事はこちら/
リリースしたアプリ(全てFlutterで開発)
個人アプリ開発で役立ったもの
おすすめの学習教材
\超初心者向けでオススメな元Udemyの講座/
\キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/
\Gitの基礎について無料で学べる/
おすすめの学習書籍
\実用的。image_pickerに関してかなり助けられた/
\Dartの基礎文法を素早くインプットできる/