FlutterでWidgetTree全体にTextStyleを適用する(DefaultTextStyle)

[チュートリアルの'Nesting rows and columns'](https://flutter.io/tutorials/layout/#nesting)で以下のように書かれているように、`DefaultTextStyle.merge`を使うことで、その下のWidgetTree全体に共通textStyleを適用することができます。

> DefaultTextStyle.merge allows you to create a default text style that is inherited by its child and all subsequent children.

この記事では、画面内のWidgetTree全体にTextStyleを適用させるパターンと、その中の一部のWidgetTreeのみにTextStyleを適用させるパターンを紹介します。

## 画面内のWidgetTree全体にTextStyleを適用させるパターン

例として、下のスクショでは、大まかに言えば3つの`Row` widgetが1つの`Column` widgetの中に入っていて、各Row widgetの中には3つの`Text` widgetがあり、それぞれ引数に`a` `b` `c` という文字リテラルが指定してあります。

さらに、この全てのText widgetの`style`プロパティで、太字など以下の**TextStyle**も指定されています。

![Screenshot_1528550502.png](https://qiita-image-store.s3.amazonaws.com/0/214755/d27a99c5-10c3-3083-d032-81a32d54d62a.png)

```dart
    var descTextStyle = TextStyle(
      color: Colors.black,
      fontWeight: FontWeight.w800,
      fontFamily: 'Roboto',
      letterSpacing: 0.5,
      fontSize: 50.0,
    );
```
```dart
  var row = Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        Text('a', style : descTextStyle),
        Text('b', style : descTextStyle),
        Text('c', style : descTextStyle),
      ],
    );
```

ただ、今回のように計9個のText widget全てに対し、**個別にstyleを指定するのは面倒くさい**ですよね。

そんな時に便利なのが、`DefaultTextStyle` widgetのファクトリメソッド`merge`です。

`merge`メソッドの引数`style`にTextStyleを指定し、`child`にwidgetを指定してあげると、このwidgetから始まるViewTreeの全ての階層に、このTextStyleが指定されます。

そのため、**この画面内の全てのWidgetTreeの全てにdescTextStyleを設定したい**という時には、以下のように`Scaffold` の`body` プロパティに`DefaultTextStyle`widgetを指定してあげれば良いと思います。
(いまだに忘れますが、この[DefaultTextStyle](https://docs.flutter.io/flutter/widgets/DefaultTextStyle-class.html)もwidgetなんですよね。)

```dart
    return new MaterialApp(
      theme: ThemeData(),
      title: 'Snapshot Title',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('DefaultTextStyleTest'),
        ),
        body: DefaultTextStyle.merge(
            style: descTextStyle,
            child: Center(
              child: column,
            )),
      ),
    );
```

## 一部のWidgetTreeのみにTextStyleを適用させるパターン

また、一部の階層だけにTextStyleを指定したい時も、簡単です。

```dart
   var column = Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        _buildRowContainer(Colors.red),
        
        //２番目のRow階層にだけdescTextStyleを指定
        DefaultTextStyle.merge(
            style: descTextStyle,
            child: _buildRowContainer(Colors.green),),
            
        _buildRowContainer(Colors.blue),
      ],
    );
```
![Screenshot_1528552240.png](https://qiita-image-store.s3.amazonaws.com/0/214755/d036051f-59e0-383a-ecaa-3ef50a2914df.png)


---


一応、main.dart全体は以下です(bodyにDefaultTextStyleを指定したバージョン)。

```dart
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  //debugPaintSizeEnabled = true;
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var descTextStyle = TextStyle(
      color: Colors.black,
      fontWeight: FontWeight.w800,
      fontFamily: 'Roboto',
      letterSpacing: 0.5,
      fontSize: 50.0,
    );

    var row = Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        Text('a'),
        Text('b'),
        Text('c'),
      ],
    );

    Container _buildRowContainer(Color color) {
      return Container(
        color: color,
        child: row,
      );
    }

    var column = Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: <Widget>[
        _buildRowContainer(Colors.red),
        _buildRowContainer(Colors.green),
        _buildRowContainer(Colors.blue),
      ],
    );

    return new MaterialApp(
      title: 'Snapshot Title',
      home:　Scaffold(
        appBar: AppBar(
          title: Text('DefaultTextStyleTest'),
        ),
        body: DefaultTextStyle.merge(
            style: descTextStyle,
            child: Center(
              child: column,
            )),
      ),
    );
  }
}

```