Unverified Commit 50cde354 authored by Darren Austin's avatar Darren Austin Committed by GitHub

Expose the duration and curve for theme animation in MaterialApp. (#107383)

parent ed65b7e2
......@@ -220,6 +220,8 @@ class MaterialApp extends StatefulWidget {
this.highContrastTheme,
this.highContrastDarkTheme,
this.themeMode = ThemeMode.system,
this.themeAnimationDuration = kThemeAnimationDuration,
this.themeAnimationCurve = Curves.linear,
this.locale,
this.localizationsDelegates,
this.localeListResolutionCallback,
......@@ -271,6 +273,8 @@ class MaterialApp extends StatefulWidget {
this.highContrastTheme,
this.highContrastDarkTheme,
this.themeMode = ThemeMode.system,
this.themeAnimationDuration = kThemeAnimationDuration,
this.themeAnimationCurve = Curves.linear,
this.locale,
this.localizationsDelegates,
this.localeListResolutionCallback,
......@@ -472,6 +476,30 @@ class MaterialApp extends StatefulWidget {
/// system what kind of theme is being used.
final ThemeMode? themeMode;
/// The duration of animated theme changes.
///
/// When the theme changes (either by the [theme], [darkTheme] or [themeMode]
/// parameters changing) it is animated to the new theme over time.
/// The [themeAnimationDuration] determines how long this animation takes.
///
/// To have the theme change immediately, you can set this to [Duration.zero].
///
/// The default is [kThemeAnimationDuration].
///
/// See also:
/// [themeAnimationCurve], which defines the curve used for the animation.
final Duration themeAnimationDuration;
/// The curve to apply when animating theme changes.
///
/// The default is [Curves.linear].
///
/// This is ignored if [themeAnimationDuration] is [Duration.zero].
///
/// See also:
/// [themeAnimationDuration], which defines how long the animation is.
final Curve themeAnimationCurve;
/// {@macro flutter.widgets.widgetsApp.color}
final Color? color;
......@@ -896,6 +924,8 @@ class _MaterialAppState extends State<MaterialApp> {
cursorColor: effectiveCursorColor,
child: AnimatedTheme(
data: theme,
duration: widget.themeAnimationDuration,
curve: widget.themeAnimationCurve,
child: widget.builder != null
? Builder(
builder: (BuildContext context) {
......
......@@ -853,6 +853,88 @@ void main() {
tester.binding.platformDispatcher.clearPlatformBrightnessTestValue();
});
testWidgets('MaterialApp animates theme changes', (WidgetTester tester) async {
final ThemeData lightTheme = ThemeData.light();
final ThemeData darkTheme = ThemeData.dark();
await tester.pumpWidget(
MaterialApp(
theme: lightTheme,
darkTheme: darkTheme,
themeMode: ThemeMode.light,
home: Builder(
builder: (BuildContext context) {
return const Scaffold();
},
),
),
);
expect(tester.widget<Material>(find.byType(Material)).color, lightTheme.scaffoldBackgroundColor);
// Change to dark theme
await tester.pumpWidget(
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.dark,
home: Builder(
builder: (BuildContext context) {
return const Scaffold();
},
),
),
);
// Wait half kThemeAnimationDuration = 200ms.
await tester.pump(const Duration(milliseconds: 100));
// Default curve is linear so background should be half way between
// the two colors.
final Color halfBGColor = Color.lerp(lightTheme.scaffoldBackgroundColor, darkTheme.scaffoldBackgroundColor, 0.5)!;
expect(tester.widget<Material>(find.byType(Material)).color, halfBGColor);
});
testWidgets('MaterialApp theme animation can be turned off', (WidgetTester tester) async {
final ThemeData lightTheme = ThemeData.light();
final ThemeData darkTheme = ThemeData.dark();
int scaffoldRebuilds = 0;
final Widget scaffold = Builder(
builder: (BuildContext context) {
scaffoldRebuilds++;
// Use Theme.of() to ensure we are building when the theme changes.
return Scaffold(backgroundColor: Theme.of(context).scaffoldBackgroundColor);
},
);
await tester.pumpWidget(
MaterialApp(
theme: lightTheme,
darkTheme: darkTheme,
themeMode: ThemeMode.light,
themeAnimationDuration: Duration.zero,
home: scaffold,
),
);
expect(tester.widget<Material>(find.byType(Material)).color, lightTheme.scaffoldBackgroundColor);
expect(scaffoldRebuilds, 1);
// Change to dark theme
await tester.pumpWidget(
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.dark,
themeAnimationDuration: Duration.zero,
home: scaffold,
),
);
// Wait for any animation to finish.
await tester.pumpAndSettle();
expect(tester.widget<Material>(find.byType(Material)).color, darkTheme.scaffoldBackgroundColor);
expect(scaffoldRebuilds, 2);
});
testWidgets('MaterialApp switches themes when the Window platformBrightness changes.', (WidgetTester tester) async {
// Mock the Window to explicitly report a light platformBrightness.
final TestWidgetsFlutterBinding binding = tester.binding;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment