6
1

More than 1 year has passed since last update.

そのDefaultTextStyle本当に大丈夫??

Posted at

はじめに

この記事はFlutter Advent Calendar 2021の14日目の記事です。

DefaultTextStyleつかっていますか?

子のTextに複数の同じTextStyleを設定したいときに親をDefaultTextStyleで囲って下のように書くことで、子のすべてのTextに対して同じTextを設定できて毎回TextでTextStyleを冗長に書くことを避けることができます。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sample'),
      ),
      body: DefaultTextStyle(
        style: TextStyle(
          fontSize: 40.0,
          color: Colors.blue,
        ),
        child: Column(
          children: [
            Text('こんにちは'),
            Text('さようなら'),
            Text('Hello, world.'),
          ],
        ),
      ),
    );
  }

Materialと組み合わせたとき

最初に以下のようなコードを用意します。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sample'),
      ),
      body: DefaultTextStyle(
        style: TextStyle(
          fontSize: 14.0,
          color: Colors.black,
        ),
        child: Column(
          children: [
            Text('こんにちは'),
            Text('さようなら'),
            Text('Hello, world.'),
          ],
        ),
      ),
    );
  }

では、次に何か背景色がついた領域に Text('さようなら')Text('Hello, world.')を入れて、タップ可能にしてタップ時にrippleを出したいときにMaterialを使ってこういうコードを書いたとします。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sample'),
      ),
      body: DefaultTextStyle(
        style: TextStyle(
          fontSize: 14.0,
          color: Colors.black,
        ),
        child: Column(
          children: [
            Text('こんにちは'),
            Material(
              color: Colors.grey,
              child: InkWell(
                onTap: () {},
                child: Column(
                  children: [
                    Text('さようなら'),
                    Text('Hello, world.'),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

うまく動いてそうですね。










ほんとでしょうか、、、?

ちょっとTextStyleで色を変えてみましょう。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sample'),
      ),
      body: DefaultTextStyle(
        style: TextStyle(
          fontSize: 14.0,
          color: Colors.blue, // Colors.black → Colors.blueに変更
        ),
        child: Column(
          children: [
            Text('こんにちは'),
            Material(
              color: Colors.grey,
              child: InkWell(
                onTap: () {},
                child: Column(
                  children: [
                    Text('さようなら'),
                    Text('Hello, world.'),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

なんだかColors.greyで囲った中のTextにTextStyleが適用されてなさそうですね🤔

これはMaterialで囲っているのが原因です。MaterialではtextStyleのプロパティが用意されていて、何も設定しないnullの状態だと中で勝手に別のTextStyleが使われる実装になっています。なので、親では Colors.blueのTextStyleを設定していますがMaterialで囲ったTextは別のTextStyleが設定されていてこのような実行結果になっています。

material.dartの中をちょっと覗いてみると、 AnimatedDefaultTextStyleというDefaultTextStyleでwrapされており、これによって外側で自分が設定したDefaultTextStyleが効いてくれません。

material.dart
      contents = AnimatedDefaultTextStyle(
        style: widget.textStyle ?? Theme.of(context).textTheme.bodyText2!,
        duration: widget.animationDuration,
        child: contents,
      );

青や極端に大きい文字をDefaultTextStyleで設定した場合は気が付きやすいとおもいますが、 AnimatedDefaultTextStyleで設定されているようなTextStyleを自分でも設定した場合違いに気が付かず意図しないTextStyleが設定されてしまうことがあるので注意が必要です。

余談

そもそもFlutterではどこでTextStyleが設定されてTextが描画されているのでしょうか。
みなさん画面を作るときにまず最初に書き始めるのが Scaffoldではないでしょうか。
親をScaffoldで囲わないでTextを配置して下のような画面をみたことがある人はいませんか?

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('あいうえお'),
    );

このWidgetを Scaffoldで囲うと

ちゃんと表示されましたね。

これはなぜなんでしょうか。

scaffold.dartの中を覗いてみると、 _ScaffoldScopeでラップされた Materialをreturnさせているのがわかります。
そのため、Scaffoldで囲わないとさきほどの AnimatedDefaultTextStyleも適用されず変なTextが表示されていたわけです。

scaffold.dart
    return _ScaffoldScope(
      hasDrawer: hasDrawer,
      geometryNotifier: _geometryNotifier,
      child: ScrollNotificationObserver(
        child: Material(
          color: widget.backgroundColor ?? themeData.scaffoldBackgroundColor,
          child: AnimatedBuilder(animation: _floatingActionButtonMoveController, builder: (BuildContext context, Widget? child) {
            return CustomMultiChildLayout(
              delegate: _ScaffoldLayout(
                extendBody: _extendBody,
                extendBodyBehindAppBar: widget.extendBodyBehindAppBar,
                minInsets: minInsets,
                minViewPadding: minViewPadding,
                currentFloatingActionButtonLocation: _floatingActionButtonLocation!,
                floatingActionButtonMoveAnimationProgress: _floatingActionButtonMoveController.value,
                floatingActionButtonMotionAnimator: _floatingActionButtonAnimator,
                geometryNotifier: _geometryNotifier,
                previousFloatingActionButtonLocation: _previousFloatingActionButtonLocation!,
                textDirection: textDirection,
                isSnackBarFloating: isSnackBarFloating,
                snackBarWidth: snackBarWidth,
              ),
              children: children,
            );
          }),
        ),
      ),
    );
  }
}

Materialで囲うとき、textStyleに特になにも指定しなかった場合勝手にTextStyleが設定されてしまうことは覚えておきましょう。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1