はじめに
通常、Flutter開発においてTextウィジェットはScaffold
内で使用されることが多いです。
以下の場合、テキストは正常に表示され、特に問題はありません。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('text'),
),
),
);
}
}

次に、Scaffoldがない場合のコード例を見てみましょう。
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Center(
child: Text('text'),
),
);
}
}

するとテキストが異常に大きく、赤文字で黄色い下線が表示されるという、エラーを連想させるような表示になります。
解決方法
① Materialを使用(シンプル)
child: Material(
child: Text('text'),
),
② DefaultTextStyleを使用
child: DefaultTextStyle(
style: TextStyle(decoration: TextDecoration.none),
child: Text('text'),
),
③ Scaffoldを使用
割愛します。
原因
この問題は、TextウィジェットがScaffoldのWidgetツリー内にないために発生します。
ではなぜ、Scaffold
の有無でスタイルが変わるのでしょうか?
公式にも書かれていますがTextウィジェットは何もスタイルを指定しない場合、一番近いDefaultTextStyleを利用します。
The style argument is optional. When omitted, the text will use the style from the closest enclosing DefaultTextStyle.
これは、Scaffoldで囲われていない場合、TextウィジェットはMaterialApp
のDefaultTextStyleを利用することを意味します。
以下MaterialAppのコードの抜粋です。
_errorTextStyle
がDefaultTextStyleとして使用されていることがわかります。
/// [MaterialApp] uses this [TextStyle] as its [DefaultTextStyle] to encourage
/// developers to be intentional about their [DefaultTextStyle].
///
/// In Material Design, most [Text] widgets are contained in [Material] widgets,
/// which sets a specific [DefaultTextStyle]. If you're seeing text that uses
/// this text style, consider putting your text in a [Material] widget (or
/// another widget that sets a [DefaultTextStyle]).
const TextStyle _errorTextStyle = TextStyle(
color: Color(0xD0FF0000),
fontFamily: 'monospace',
fontSize: 48.0,
fontWeight: FontWeight.w900,
decoration: TextDecoration.underline,
decorationColor: Color(0xFFFFFF00),
decorationStyle: TextDecorationStyle.double,
debugLabel: 'fallback style; consider putting your text in a Material',
);
このコードから、Scaffoldで作られるDefaultTextStyleではなく、MaterialAppで作られるDefaultTextStyleがTextウィジェットに適用されることがわかりました。
事例
しかし、特定のシナリオではTextウィジェットをScaffoldの外で使用する必要がある場合があるかもしれません。これには以下のような状況が含まれます。
-
非同期処理後のダイアログ表示
データ取得などの非同期処理が完了した後に表示されるダイアログ内でTextウィジェットを使用する場合。 -
ローディング画面の表示
データの読み込みを開始する際にローディング画面を表示し、その中で「読み込み中...」などのメッセージをTextウィジェットで表示する場合。
他のシナリオも考えられますが、このような例では、ScaffoldのWidgetツリー外に配置される場合がありますので、注意して実装していきたいです。
参考