0

Some parts of my app use a different color scheme, but the color change is not applied to the date picker widget.

Is it another theme bug? How to fix it?

import 'package:flutter/material.dart';

main() {
  runApp(
    MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.light(
          primary: Colors.red,
          secondary: Colors.red,
        ),
        // https://stackoverflow.com/a/72808301
        toggleableActiveColor: Colors.red,
      ),
      home: _TestTheme1(),
    ),
  );
}

class _TestTheme1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Red?')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _TestWidgets(),
            FloatingActionButton(
              child: Icon(Icons.arrow_forward),
              onPressed: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return _TestTheme2();
                }));
              },
            ),
          ],
        ),
      ),
    );
  }
}

class _TestTheme2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var theme = ThemeData(
      colorScheme: ColorScheme.light(
        primary: Colors.green,
        secondary: Colors.green,
      ),
      // https://stackoverflow.com/a/72808301
      toggleableActiveColor: Colors.green,
    );
    var child = Scaffold(
      appBar: AppBar(title: Text('Green?')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            _TestWidgets(),
            ElevatedButton(
              child: Text('Pick date'),
              onPressed: () {
                var now = DateTime.now();
                // BUG: Should be green, not red!
                showDatePicker(
                  context: context,
                  initialDate: now,
                  firstDate: DateTime(now.year - 1, now.month, now.day),
                  lastDate: DateTime(now.year + 1, now.month, now.day),
                );
              },
            ),
          ],
        ),
      ),
    );
    return Theme(data: theme, child: child);
    // return MaterialApp(theme: theme, home: child);
  }
}

class _TestWidgets extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Checkbox(value: true, onChanged: (value) {}),
        Switch(value: true, onChanged: (value) {}),
      ],
    );
  }
}
lepsch
  • 8,927
  • 5
  • 24
  • 44
Patrick
  • 3,578
  • 5
  • 31
  • 53

2 Answers2

1

Move the Theme(data: theme, child: child); to the builder property of showDatPicker.

Something like below

showDatePicker(
  context: context,
  initialDate: now,
  firstDate: DateTime(now.year - 1, now.month, now.day),
  lastDate: DateTime(now.year + 1, now.month, now.day),
  builder: (context, child) {
    return Theme(data: theme, child: child);
  },
);

lepsch
  • 8,927
  • 5
  • 24
  • 44
  • Maybe this answer would help also with theming the various parts of the `showDatePicker`: https://stackoverflow.com/questions/73670661/how-to-change-font-in-flutter-date-picker/73672094#73672094 – lepsch Sep 10 '22 at 14:47
  • OK but this is a hack. You have to do this for every showDatePicker. The purpose of Theme should be to avoid this. – Patrick Sep 10 '22 at 14:51
  • It's not a hack... it's the way to theme it. The only other way is to change `MaterialApp` theme property but this would change the entire app theming. You can create a function that calls `showDatePicker` with the theming you'd like it to be and change all other sites to call this function instead. – lepsch Sep 10 '22 at 14:53
  • 1
    Also, [from the docs](https://api.flutter.dev/flutter/material/showDatePicker.html): _The `builder` parameter can be used to wrap the dialog widget to add inherited widgets like `Theme`._ – lepsch Sep 10 '22 at 14:58
  • 1
    Sorry but as I said, this is a hack. And creating a function to call showDatePicker is more hack. The purpose of ThemeData is precisely to apply a theme automatically to all descendant widgets. This works for other widgets (except theming bugs, see toggleableActiveColor) and should work for date picker also. – Patrick Sep 10 '22 at 15:24
  • 1
    You think this is a hack even though the official docs say otherwise: [The builder parameter can be used to wrap the dialog widget to add inherited widgets like **`Theme`**](https://api.flutter.dev/flutter/material/showDatePicker.html). Ok then. – lepsch Sep 10 '22 at 15:29
  • And the style parameter of Text can be used to set the text font, etc. But I don't want to do this for every Text widget, do you? – Patrick Sep 10 '22 at 15:32
  • Of course not. That's why we should use the [`Theme`](https://api.flutter.dev/flutter/material/Theme-class.html) widget and wrap whatever child we'd like to customize. Adding the `builder` and wrapping the child is the way to change `showDatePicker` as the official docs say. – lepsch Sep 10 '22 at 15:40
0

The fix is to add a Builder so that showDatePicker gets the right themed context.

In _TestTheme2 just replace Scaffold(...) with Builder(builder: (context) => Scaffold(...)) and voilà.

Patrick
  • 3,578
  • 5
  • 31
  • 53