Search code examples
flutterflutter-theme

How to change the Text color for a subtree in Flutter?


I want that every Text inside a particular Widget will have a white color, although they all can have different sizes. I know I can change every singe Text to have a white color, but I want to make it smart and change the Theme for that particular Widget.

I tried this:

DefaultTextStyle.merge(
  style: TextStyle(color: Colors.white),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      Text('Text 1',
        style: Theme.of(context).textTheme.title,
      ),
      Text('Text 2')
    ],
  ),
),

The problem is Text 1 becomes black and Text 2 is white as I wanted.

I thought that using DefaultTextStyle.merge I would still be able to use Theme.of(context) to get the general TextTheme, still maintaining the changes over DefaultTextStyle but apparently I am wrong.

What's the correct way of changing a sub-tree's text color, while being able to access the rest of the original Theme?


Solution

  • The issue here is that you are overwriting the style using this style: Theme.of(context).textTheme.title, it's getting the title style from textTheme from you the current Theme of your app.

    A possible solution is to use a custom style but copying the color property, like this :

    DefaultTextStyle(
              style: TextStyle(color: Colors.white),
              child: Builder(
                builder: (context) {
                  return Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        'Text 1',
                        style: Theme.of(context).textTheme.title.copyWith(
                            color: DefaultTextStyle.of(context).style.color),
                      ),
                      Text('Text 2')
                    ],
                  );
                },
              ),
            ),
    

    The easy way is just not using the textTheme from your Theme, just write your own style without specifying the color, like this:

    DefaultTextStyle(
              style: TextStyle(color: Colors.white),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'Text 1',
                    //change the style without changing the color
                    style: TextStyle(fontSize: 40),
                  ),
                  Text('Text 2')
                ],
              ),
            ),
    

    UPDATE

    I found another way what you can use :

    Theme(
              data: Theme.of(context).copyWith(
                textTheme: Theme.of(context).textTheme.apply(
                      bodyColor: Colors.white,
                      displayColor: Colors.white,
                    ),
              ),
              child: DefaultTextStyle(
                style: TextStyle(color: Colors.white),
                child: Builder(
                  builder: (context) {
                    return Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text(
                          'Text 1',
                          style: Theme.of(context).textTheme.title,
                        ),
                        Text('Text 2')
                      ],
                    );
                  },
                ),
              ),
            ),
    

    If you don't want to use the Builder widget, use the Theme.of(context).copyWith on the parent widget (of your statelesswidget/statefulwidget).