Skip to content

Commit a8f9d4c

Browse files
authored
AppBar draws its defaults from theme.colorScheme (flutter#69251)
1 parent 99e0d3b commit a8f9d4c

File tree

4 files changed

+254
-95
lines changed

4 files changed

+254
-95
lines changed

packages/flutter/lib/src/material/app_bar.dart

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart';
1111

1212
import 'app_bar_theme.dart';
1313
import 'back_button.dart';
14+
import 'color_scheme.dart';
1415
import 'constants.dart';
1516
import 'debug.dart';
1617
import 'flexible_space_bar.dart';
@@ -196,6 +197,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
196197
this.shadowColor,
197198
this.shape,
198199
this.backgroundColor,
200+
this.foregroundColor,
199201
this.brightness,
200202
this.iconTheme,
201203
this.actionsIconTheme,
@@ -357,20 +359,68 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
357359
/// zero.
358360
final ShapeBorder? shape;
359361

360-
/// The color to use for the app bar's material. Typically this should be set
361-
/// along with [brightness], [iconTheme], [textTheme].
362+
/// The fill color to use for the app bar's [Material].
362363
///
363-
/// If this property is null, then [AppBarTheme.color] of
364-
/// [ThemeData.appBarTheme] is used. If that is also null, then
365-
/// [ThemeData.primaryColor] is used.
364+
/// If null, then the [AppBarTheme.color] is used. If that value is also
365+
/// null, then [AppBar] uses the overall theme's [ColorScheme.primary] if the
366+
/// overall theme's brightness is [Brightness.light], and [ColorScheme.surface]
367+
/// if the overall theme's [brightness] is [Brightness.dark].
368+
///
369+
/// See also:
370+
///
371+
/// * [foregroundColor], which specifies the color for icons and text within
372+
/// the app bar.
373+
/// * [Theme.of], which returns the current overall Material theme as
374+
/// a [ThemeData].
375+
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
376+
/// default colors are based on.
377+
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
378+
/// is light or dark.
366379
final Color? backgroundColor;
367380

368-
/// The brightness of the app bar's material. Typically this is set along
369-
/// with [backgroundColor], [iconTheme], [textTheme].
381+
/// The default color for [Text] and [Icon]s within the app bar.
370382
///
371-
/// If this property is null, then [AppBarTheme.brightness] of
372-
/// [ThemeData.appBarTheme] is used. If that is also null, then
373-
/// [ThemeData.primaryColorBrightness] is used.
383+
/// If null, then [AppBarTheme.foregroundColor] is used. If that
384+
/// value is also null, then [AppBar] uses the overall theme's
385+
/// [ColorScheme.onPrimary] if the overall theme's brightness is
386+
/// [Brightness.light], and [ColorScheme.onSurface] if the overall
387+
/// theme's [brightness] is [Brightness.dark].
388+
///
389+
/// This color is used to configure [DefaultTextStyle] that contains
390+
/// the app bar's children, and the default [IconTheme] widgets that
391+
/// are created if [iconTheme] and [actionsIconTheme] are null.
392+
///
393+
/// See also:
394+
///
395+
/// * [backgroundColor], which specifies the app bar's background color.
396+
/// * [Theme.of], which returns the current overall Material theme as
397+
/// a [ThemeData].
398+
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
399+
/// default colors are based on.
400+
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
401+
/// is light or dark.
402+
final Color? foregroundColor;
403+
404+
/// Determines the brightness of the [SystemUiOverlayStyle]: for
405+
/// [Brightness.dark], [SystemUiOverlayStyle.light] is used and fo
406+
/// [Brightness.light], [SystemUiOverlayStyle.dark] is used.
407+
///
408+
/// If this value is null then [AppBarTheme.brightness] is used
409+
/// and if that's null then overall theme's brightness is used.
410+
///
411+
/// The AppBar is built within a `AnnotatedRegion<SystemUiOverlayStyle>`
412+
/// which causes [SystemChrome.setSystemUIOverlayStyle] to be called
413+
/// automatically. Apps should not enclose the AppBar with
414+
/// their own [AnnotatedRegion].
415+
///
416+
/// See also:
417+
///
418+
/// * [Theme.of], which returns the current overall Material theme as
419+
/// a [ThemeData].
420+
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
421+
/// default colors are based on.
422+
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
423+
/// is light or dark.
374424
final Brightness? brightness;
375425

376426
/// The color, opacity, and size to use for app bar icons. Typically this
@@ -499,6 +549,7 @@ class _AppBarState extends State<AppBar> {
499549
assert(!widget.primary || debugCheckHasMediaQuery(context));
500550
assert(debugCheckHasMaterialLocalizations(context));
501551
final ThemeData theme = Theme.of(context);
552+
final ColorScheme colorScheme = theme.colorScheme;
502553
final AppBarTheme appBarTheme = AppBarTheme.of(context);
503554
final ScaffoldState? scaffold = Scaffold.maybeOf(context);
504555
final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context);
@@ -510,18 +561,25 @@ class _AppBarState extends State<AppBar> {
510561

511562
final double toolbarHeight = widget.toolbarHeight ?? kToolbarHeight;
512563

564+
final Color backgroundColor = widget.backgroundColor
565+
?? appBarTheme.color
566+
?? (colorScheme.brightness == Brightness.dark ? colorScheme.surface : colorScheme.primary);
567+
final Color foregroundColor = widget.foregroundColor
568+
?? appBarTheme.foregroundColor
569+
?? (colorScheme.brightness == Brightness.dark ? colorScheme.onSurface : colorScheme.onPrimary);
570+
513571
IconThemeData overallIconTheme = widget.iconTheme
514572
?? appBarTheme.iconTheme
515-
?? theme.primaryIconTheme;
573+
?? theme.iconTheme.copyWith(color: foregroundColor);
516574
IconThemeData actionsIconTheme = widget.actionsIconTheme
517575
?? appBarTheme.actionsIconTheme
518576
?? overallIconTheme;
519577
TextStyle? centerStyle = widget.textTheme?.headline6
520578
?? appBarTheme.textTheme?.headline6
521-
?? theme.primaryTextTheme.headline6;
579+
?? theme.primaryTextTheme.headline6?.copyWith(color: foregroundColor);
522580
TextStyle? sideStyle = widget.textTheme?.bodyText2
523581
?? appBarTheme.textTheme?.bodyText2
524-
?? theme.primaryTextTheme.bodyText2;
582+
?? theme.primaryTextTheme.bodyText2?.copyWith(color: foregroundColor);
525583

526584
if (widget.toolbarOpacity != 1.0) {
527585
final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity);
@@ -530,10 +588,10 @@ class _AppBarState extends State<AppBar> {
530588
if (sideStyle?.color != null)
531589
sideStyle = sideStyle!.copyWith(color: sideStyle.color!.withOpacity(opacity));
532590
overallIconTheme = overallIconTheme.copyWith(
533-
opacity: opacity * (overallIconTheme.opacity ?? 1.0)
591+
opacity: opacity * (overallIconTheme.opacity ?? 1.0),
534592
);
535593
actionsIconTheme = actionsIconTheme.copyWith(
536-
opacity: opacity * (actionsIconTheme.opacity ?? 1.0)
594+
opacity: opacity * (actionsIconTheme.opacity ?? 1.0),
537595
);
538596
}
539597

@@ -707,21 +765,19 @@ class _AppBarState extends State<AppBar> {
707765
],
708766
);
709767
}
768+
710769
final Brightness brightness = widget.brightness
711770
?? appBarTheme.brightness
712-
?? theme.primaryColorBrightness;
771+
?? colorScheme.brightness;
713772
final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark
714773
? SystemUiOverlayStyle.light
715774
: SystemUiOverlayStyle.dark;
716-
717775
return Semantics(
718776
container: true,
719777
child: AnnotatedRegion<SystemUiOverlayStyle>(
720778
value: overlayStyle,
721779
child: Material(
722-
color: widget.backgroundColor
723-
?? appBarTheme.color
724-
?? theme.primaryColor,
780+
color: backgroundColor,
725781
elevation: widget.elevation
726782
?? appBarTheme.elevation
727783
?? _defaultElevation,

packages/flutter/lib/src/material/app_bar_theme.dart

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class AppBarTheme with Diagnosticable {
3333
const AppBarTheme({
3434
this.brightness,
3535
this.color,
36+
this.foregroundColor,
3637
this.elevation,
3738
this.shadowColor,
3839
this.iconTheme,
@@ -42,16 +43,66 @@ class AppBarTheme with Diagnosticable {
4243
this.titleSpacing,
4344
});
4445

45-
/// Default value for [AppBar.brightness].
46+
/// AppBar uses this value to determine the default (background) [color] and
47+
/// [foregroundColor] as well as the app bar's [SystemUiOverlayStyle].
4648
///
47-
/// If null, [AppBar] uses [ThemeData.primaryColorBrightness].
49+
/// For [Brightness.dark], [SystemUiOverlayStyle.light] is used and for
50+
/// [Brightness.light], [SystemUiOverlayStyle.dark] is used.
51+
///
52+
/// See also:
53+
///
54+
/// * [AppBar.brightness], which overrides the this value and the overall
55+
/// theme's [ColorScheme.brightness].
56+
/// * [Theme.of], which returns the current overall Material theme as
57+
/// a [ThemeData].
58+
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
59+
/// default colors are based on.
60+
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
61+
/// is light or dark.
4862
final Brightness? brightness;
4963

50-
/// Default value for [AppBar.backgroundColor].
64+
/// The app bar's background color.
65+
///
66+
/// If null, [AppBar] uses the overall theme's [ColorScheme.primary] if the
67+
/// overall theme's brightness is [Brightness.light], and [ColorScheme.surface]
68+
/// if the overall theme's [brightness] is [Brightness.dark].
5169
///
52-
/// If null, [AppBar] uses [ThemeData.primaryColor].
70+
/// See also:
71+
///
72+
/// * [AppBar.backgroundColor], which specifies the AppBar's background color
73+
/// and overrides the background color defined by this theme.
74+
/// * [foregroundColor], which specifies the color for icons and text within
75+
/// the app bar.
76+
/// * [Theme.of], which returns the current overall Material theme as
77+
/// a [ThemeData].
78+
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
79+
/// default colors are based on.
80+
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
81+
/// is light or dark.
5382
final Color? color;
5483

84+
/// The default color for [Text] and [Icon]s within the app bar.
85+
///
86+
/// If null, [AppBar] uses the overall theme's [ColorScheme.onPrimary] if the
87+
/// overall theme's brightness is [Brightness.light], and [ColorScheme.onSurface]
88+
/// if the overall theme's [brightness] is [Brightness.dark].
89+
///
90+
/// This color is used to configure [DefaultTextStyle] and [IconTheme]
91+
/// widgets.
92+
///
93+
/// See also:
94+
///
95+
/// * [AppBar.foregroundColor], which specifies the app bar's text and icon
96+
/// colors and overrides the foreground color defined by this theme.
97+
/// * [color], which specifies the app bar's background color.
98+
/// * [Theme.of], which returns the current overall Material theme as
99+
/// a [ThemeData].
100+
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
101+
/// default colors are based on.
102+
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
103+
/// is light or dark.
104+
final Color? foregroundColor;
105+
55106
/// Default value for [AppBar.elevation].
56107
///
57108
/// If null, [AppBar] uses a default value of 4.0.
@@ -93,6 +144,7 @@ class AppBarTheme with Diagnosticable {
93144
IconThemeData? actionsIconTheme,
94145
Brightness? brightness,
95146
Color? color,
147+
Color? foregroundColor,
96148
double? elevation,
97149
Color? shadowColor,
98150
IconThemeData? iconTheme,
@@ -103,6 +155,7 @@ class AppBarTheme with Diagnosticable {
103155
return AppBarTheme(
104156
brightness: brightness ?? this.brightness,
105157
color: color ?? this.color,
158+
foregroundColor: foregroundColor ?? this.foregroundColor,
106159
elevation: elevation ?? this.elevation,
107160
shadowColor: shadowColor ?? this.shadowColor,
108161
iconTheme: iconTheme ?? this.iconTheme,
@@ -128,6 +181,7 @@ class AppBarTheme with Diagnosticable {
128181
return AppBarTheme(
129182
brightness: t < 0.5 ? a?.brightness : b?.brightness,
130183
color: Color.lerp(a?.color, b?.color, t),
184+
foregroundColor: Color.lerp(a?.foregroundColor, b?.foregroundColor, t),
131185
elevation: lerpDouble(a?.elevation, b?.elevation, t),
132186
shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
133187
iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t),
@@ -143,6 +197,7 @@ class AppBarTheme with Diagnosticable {
143197
return hashValues(
144198
brightness,
145199
color,
200+
foregroundColor,
146201
elevation,
147202
shadowColor,
148203
iconTheme,
@@ -162,6 +217,7 @@ class AppBarTheme with Diagnosticable {
162217
return other is AppBarTheme
163218
&& other.brightness == brightness
164219
&& other.color == color
220+
&& other.foregroundColor == foregroundColor
165221
&& other.elevation == elevation
166222
&& other.shadowColor == shadowColor
167223
&& other.iconTheme == iconTheme
@@ -176,6 +232,7 @@ class AppBarTheme with Diagnosticable {
176232
super.debugFillProperties(properties);
177233
properties.add(DiagnosticsProperty<Brightness>('brightness', brightness, defaultValue: null));
178234
properties.add(ColorProperty('color', color, defaultValue: null));
235+
properties.add(ColorProperty('foregroundColor', foregroundColor, defaultValue: null));
179236
properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null));
180237
properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
181238
properties.add(DiagnosticsProperty<IconThemeData>('iconTheme', iconTheme, defaultValue: null));

packages/flutter/test/material/app_bar_test.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,7 @@ void main() {
17691769
));
17701770

17711771
expect(darkTheme.primaryColorBrightness, Brightness.dark);
1772+
expect(darkTheme.colorScheme.brightness, Brightness.dark);
17721773
expect(SystemChrome.latestStyle, const SystemUiOverlayStyle(
17731774
statusBarBrightness: Brightness.dark,
17741775
statusBarIconBrightness: Brightness.light,
@@ -1777,14 +1778,17 @@ void main() {
17771778

17781779
testWidgets('AppBar draws a dark system bar for a light background', (WidgetTester tester) async {
17791780
final ThemeData lightTheme = ThemeData(primaryColor: Colors.white);
1780-
await tester.pumpWidget(MaterialApp(
1781-
theme: lightTheme,
1782-
home: Scaffold(
1783-
appBar: AppBar(title: const Text('test')),
1781+
await tester.pumpWidget(
1782+
MaterialApp(
1783+
theme: lightTheme,
1784+
home: Scaffold(
1785+
appBar: AppBar(title: const Text('test')),
1786+
),
17841787
),
1785-
));
1788+
);
17861789

17871790
expect(lightTheme.primaryColorBrightness, Brightness.light);
1791+
expect(lightTheme.colorScheme.brightness, Brightness.light);
17881792
expect(SystemChrome.latestStyle, const SystemUiOverlayStyle(
17891793
statusBarBrightness: Brightness.light,
17901794
statusBarIconBrightness: Brightness.dark,

0 commit comments

Comments
 (0)