Normalize BottomAppBarTheme (#168586)

This PR is to make `BottomAppBarTheme` conform to Flutter Material's
conventions for component themes:

- Added a `BottomAppBarThemeData` class which defines overrides for the
defaults for `BottomAppBar` properties.
- Added `BottomAppBarTheme` constructor parameters:
`BottomAppBarThemeData? data` and `Widget? child`. This is now the
preferred way to configure a `BottomAppBarTheme`:

```dart
BottomAppBarTheme(
	data: BottomAppBarThemeData(
	    color: xxx,
	    height: xxx,
	    elevation: xxx,
	    shape: xxx,
	    ...
	  ),
  	child: const BottomAppBar()
)
```
These two properties are made nullable to not break existing apps which
has customized `ThemeData.bottomAppBarTheme`.

- Update `BottomAppBarTheme` to be an `InheritedWidget` subclass.
- Changed the type of component theme defaults from `BottomAppBarTheme`
to `BottomAppBarThemeData`.
- Changed the `BottomAppBarTheme bottomAppBarTheme` property to
`BottomAppBarThemeData bottomAppBarTheme` in `ThemeData` and
`ThemeData.copyWith()`. This may cause breaking changes, a migration
guide will be created on website repo.
- Add new tests for `BottomAppBarThemeData` and update the existing
`BottomAppBarTheme` tests. And also turn to `true` for `useMaterial3`
(along with usages accordingly) at the common method `_withTheme()`
since `useMaterial3` is true by default.
- Addresses the "theme normalization" sub-project within #91772.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Signed-off-by: huycozy <huy@nevercode.io>
This commit is contained in:
Huy 2025-05-15 00:38:18 +07:00 committed by GitHub
parent a3176830dc
commit 494b08b420
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 400 additions and 80 deletions

View File

@ -152,7 +152,7 @@ class _RestorableEmailState extends RestorableListenable<EmailStore> {
ThemeData _buildReplyLightTheme(BuildContext context) { ThemeData _buildReplyLightTheme(BuildContext context) {
final ThemeData base = ThemeData(); final ThemeData base = ThemeData();
return base.copyWith( return base.copyWith(
bottomAppBarTheme: const BottomAppBarTheme(color: ReplyColors.blue700), bottomAppBarTheme: const BottomAppBarThemeData(color: ReplyColors.blue700),
bottomSheetTheme: BottomSheetThemeData( bottomSheetTheme: BottomSheetThemeData(
backgroundColor: ReplyColors.blue700, backgroundColor: ReplyColors.blue700,
modalBackgroundColor: Colors.white.withOpacity(0.7), modalBackgroundColor: Colors.white.withOpacity(0.7),
@ -192,7 +192,7 @@ ThemeData _buildReplyLightTheme(BuildContext context) {
ThemeData _buildReplyDarkTheme(BuildContext context) { ThemeData _buildReplyDarkTheme(BuildContext context) {
final ThemeData base = ThemeData.dark(); final ThemeData base = ThemeData.dark();
return base.copyWith( return base.copyWith(
bottomAppBarTheme: const BottomAppBarTheme(color: ReplyColors.darkBottomAppBarBackground), bottomAppBarTheme: const BottomAppBarThemeData(color: ReplyColors.darkBottomAppBarBackground),
bottomSheetTheme: BottomSheetThemeData( bottomSheetTheme: BottomSheetThemeData(
backgroundColor: ReplyColors.darkDrawerBackground, backgroundColor: ReplyColors.darkDrawerBackground,
modalBackgroundColor: Colors.black.withOpacity(0.7), modalBackgroundColor: Colors.black.withOpacity(0.7),

View File

@ -20,7 +20,7 @@ class MaterialDemoThemeData {
color: _colorScheme.primary, color: _colorScheme.primary,
iconTheme: IconThemeData(color: _colorScheme.onPrimary), iconTheme: IconThemeData(color: _colorScheme.onPrimary),
), ),
bottomAppBarTheme: BottomAppBarTheme(color: _colorScheme.primary), bottomAppBarTheme: BottomAppBarThemeData(color: _colorScheme.primary),
checkboxTheme: CheckboxThemeData( checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) { fillColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) { if (states.contains(MaterialState.disabled)) {

View File

@ -14,7 +14,7 @@ class BottomAppBarTemplate extends TokenTemplate {
@override @override
String generate() => ''' String generate() => '''
class _${blockName}DefaultsM3 extends BottomAppBarTheme { class _${blockName}DefaultsM3 extends BottomAppBarThemeData {
_${blockName}DefaultsM3(this.context) _${blockName}DefaultsM3(this.context)
: super( : super(
elevation: ${elevation('md.comp.bottom-app-bar.container')}, elevation: ${elevation('md.comp.bottom-app-bar.container')},

View File

@ -67,8 +67,8 @@ class BottomAppBar extends StatefulWidget {
/// The [clipBehavior] argument defaults to [Clip.none]. /// The [clipBehavior] argument defaults to [Clip.none].
/// Additionally, [elevation] must be non-negative. /// Additionally, [elevation] must be non-negative.
/// ///
/// If [color], [elevation], or [shape] are null, their [BottomAppBarTheme] values will be used. /// If [color], [elevation], or [shape] are null, their [BottomAppBarThemeData] values will be used.
/// If the corresponding [BottomAppBarTheme] property is null, then the default /// If the corresponding [BottomAppBarThemeData] property is null, then the default
/// specified in the property's documentation will be used. /// specified in the property's documentation will be used.
const BottomAppBar({ const BottomAppBar({
super.key, super.key,
@ -100,7 +100,7 @@ class BottomAppBar extends StatefulWidget {
/// The bottom app bar's background color. /// The bottom app bar's background color.
/// ///
/// If this property is null then [BottomAppBarTheme.color] of /// If this property is null then [BottomAppBarThemeData.color] of
/// [ThemeData.bottomAppBarTheme] is used. If that's null and [ThemeData.useMaterial3] /// [ThemeData.bottomAppBarTheme] is used. If that's null and [ThemeData.useMaterial3]
/// is true, the default value is [ColorScheme.surface]; if [ThemeData.useMaterial3] /// is true, the default value is [ColorScheme.surface]; if [ThemeData.useMaterial3]
/// is false, then the default value is `Color(0xFF424242)` in dark theme and /// is false, then the default value is `Color(0xFF424242)` in dark theme and
@ -113,14 +113,14 @@ class BottomAppBar extends StatefulWidget {
/// This controls the size of the shadow below the bottom app bar. The /// This controls the size of the shadow below the bottom app bar. The
/// value is non-negative. /// value is non-negative.
/// ///
/// If this property is null then [BottomAppBarTheme.elevation] of /// If this property is null then [BottomAppBarThemeData.elevation] of
/// [ThemeData.bottomAppBarTheme] is used. If that's null and /// [ThemeData.bottomAppBarTheme] is used. If that's null and
/// [ThemeData.useMaterial3] is true, than the default value is 3 else is 8. /// [ThemeData.useMaterial3] is true, than the default value is 3 else is 8.
final double? elevation; final double? elevation;
/// The notch that is made for the floating action button. /// The notch that is made for the floating action button.
/// ///
/// If this property is null then [BottomAppBarTheme.shape] of /// If this property is null then [BottomAppBarThemeData.shape] of
/// [ThemeData.bottomAppBarTheme] is used. If that's null then the shape will /// [ThemeData.bottomAppBarTheme] is used. If that's null then the shape will
/// be rectangular with no notch. /// be rectangular with no notch.
final NotchedShape? shape; final NotchedShape? shape;
@ -143,7 +143,7 @@ class BottomAppBar extends StatefulWidget {
/// which provide more flexibility. The intention is to eventually remove surface tint color from /// which provide more flexibility. The intention is to eventually remove surface tint color from
/// the framework. /// the framework.
/// ///
/// If this property is null, then [BottomAppBarTheme.surfaceTintColor] /// If this property is null, then [BottomAppBarThemeData.surfaceTintColor]
/// of [ThemeData.bottomAppBarTheme] is used. If that is also null, the default /// of [ThemeData.bottomAppBarTheme] is used. If that is also null, the default
/// value is [Colors.transparent]. /// value is [Colors.transparent].
/// ///
@ -154,7 +154,7 @@ class BottomAppBar extends StatefulWidget {
/// The color of the shadow below the app bar. /// The color of the shadow below the app bar.
/// ///
/// If this property is null, then [BottomAppBarTheme.shadowColor] of /// If this property is null, then [BottomAppBarThemeData.shadowColor] of
/// [ThemeData.bottomAppBarTheme] is used. If that is also null, the default value /// [ThemeData.bottomAppBarTheme] is used. If that is also null, the default value
/// is fully opaque black for Material 2, and transparent for Material 3. /// is fully opaque black for Material 2, and transparent for Material 3.
/// ///
@ -188,8 +188,8 @@ class _BottomAppBarState extends State<BottomAppBar> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
final bool isMaterial3 = theme.useMaterial3; final bool isMaterial3 = theme.useMaterial3;
final BottomAppBarTheme babTheme = BottomAppBarTheme.of(context); final BottomAppBarThemeData babTheme = BottomAppBarTheme.of(context);
final BottomAppBarTheme defaults = final BottomAppBarThemeData defaults =
isMaterial3 ? _BottomAppBarDefaultsM3(context) : _BottomAppBarDefaultsM2(context); isMaterial3 ? _BottomAppBarDefaultsM3(context) : _BottomAppBarDefaultsM2(context);
final bool hasFab = Scaffold.of(context).hasFloatingActionButton; final bool hasFab = Scaffold.of(context).hasFloatingActionButton;
@ -291,7 +291,7 @@ class _BottomAppBarClipper extends CustomClipper<Path> {
} }
} }
class _BottomAppBarDefaultsM2 extends BottomAppBarTheme { class _BottomAppBarDefaultsM2 extends BottomAppBarThemeData {
const _BottomAppBarDefaultsM2(this.context) : super(elevation: 8.0); const _BottomAppBarDefaultsM2(this.context) : super(elevation: 8.0);
final BuildContext context; final BuildContext context;
@ -315,7 +315,7 @@ class _BottomAppBarDefaultsM2 extends BottomAppBarTheme {
// dev/tools/gen_defaults/bin/gen_defaults.dart. // dev/tools/gen_defaults/bin/gen_defaults.dart.
// dart format off // dart format off
class _BottomAppBarDefaultsM3 extends BottomAppBarTheme { class _BottomAppBarDefaultsM3 extends BottomAppBarThemeData {
_BottomAppBarDefaultsM3(this.context) _BottomAppBarDefaultsM3(this.context)
: super( : super(
elevation: 3.0, elevation: 3.0,

View File

@ -15,11 +15,11 @@ import 'theme.dart';
/// Defines default property values for descendant [BottomAppBar] widgets. /// Defines default property values for descendant [BottomAppBar] widgets.
/// ///
/// Descendant widgets obtain the current [BottomAppBarTheme] object using /// Descendant widgets obtain the current [BottomAppBarThemeData] object using
/// `BottomAppBarTheme.of(context)`. Instances of [BottomAppBarTheme] can be /// `[BottomAppBarTheme.of]`. Instances of [BottomAppBarThemeData] can be
/// customized with [BottomAppBarTheme.copyWith]. /// customized with [BottomAppBarThemeData.copyWith].
/// ///
/// Typically a [BottomAppBarTheme] is specified as part of the overall [Theme] /// Typically a [BottomAppBarThemeData] is specified as part of the overall [Theme]
/// with [ThemeData.bottomAppBarTheme]. /// with [ThemeData.bottomAppBarTheme].
/// ///
/// All [BottomAppBarTheme] properties are `null` by default. When null, the /// All [BottomAppBarTheme] properties are `null` by default. When null, the
@ -30,9 +30,192 @@ import 'theme.dart';
/// * [ThemeData], which describes the overall theme information for the /// * [ThemeData], which describes the overall theme information for the
/// application. /// application.
@immutable @immutable
class BottomAppBarTheme with Diagnosticable { class BottomAppBarTheme extends InheritedTheme with Diagnosticable {
/// Creates a theme that can be used for [ThemeData.bottomAppBarTheme]. /// Creates a theme that can be used for [ThemeData.bottomAppBarTheme].
const BottomAppBarTheme({ const BottomAppBarTheme({
super.key,
Color? color,
double? elevation,
NotchedShape? shape,
double? height,
Color? surfaceTintColor,
Color? shadowColor,
EdgeInsetsGeometry? padding,
BottomAppBarThemeData? data,
Widget? child,
}) : assert(
data == null ||
(color ??
elevation ??
shape ??
height ??
surfaceTintColor ??
shadowColor ??
padding) ==
null,
),
_color = color,
_elevation = elevation,
_shape = shape,
_height = height,
_surfaceTintColor = surfaceTintColor,
_shadowColor = shadowColor,
_padding = padding,
_data = data,
super(child: child ?? const SizedBox.shrink());
final BottomAppBarThemeData? _data;
final Color? _color;
final double? _elevation;
final NotchedShape? _shape;
final double? _height;
final Color? _surfaceTintColor;
final Color? _shadowColor;
final EdgeInsetsGeometry? _padding;
/// Overrides the default value for [BottomAppBar.color].
///
/// This property is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.color] property in [data] instead.
Color? get color => _data != null ? _data.color : _color;
/// Overrides the default value for [BottomAppBar.elevation].
///
/// This property is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.elevation] property in [data] instead.
double? get elevation => _data != null ? _data.elevation : _elevation;
/// Overrides the default value for [BottomAppBar.shape].
///
/// This property is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.shape] property in [data] instead.
NotchedShape? get shape => _data != null ? _data.shape : _shape;
/// Overrides the default value for [BottomAppBar.height].
///
/// This property is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.height] property in [data] instead.
double? get height => _data != null ? _data.height : _height;
/// Overrides the default value for [BottomAppBar.surfaceTintColor].
///
/// This property is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.surfaceTintColor] property in [data] instead.
///
/// If null, [BottomAppBar] will not display an overlay color.
///
/// See [Material.surfaceTintColor] for more details.
Color? get surfaceTintColor => _data != null ? _data.surfaceTintColor : _surfaceTintColor;
/// Overrides the default value for [BottomAppBar.shadowColor].
///
/// This property is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.shadowColor] property in [data] instead.
Color? get shadowColor => _data != null ? _data.shadowColor : _shadowColor;
/// Overrides the default value for [BottomAppBar.padding].
///
/// This property is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.padding] property in [data] instead.
EdgeInsetsGeometry? get padding => _data != null ? _data.padding : _padding;
/// The properties used for all descendant [BottomAppBar] widgets.
BottomAppBarThemeData get data =>
_data ??
BottomAppBarThemeData(
color: _color,
elevation: _elevation,
shape: _shape,
height: _height,
surfaceTintColor: _surfaceTintColor,
shadowColor: _shadowColor,
padding: _padding,
);
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
///
/// This method is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.copyWith] method instead.
BottomAppBarTheme copyWith({
Color? color,
double? elevation,
NotchedShape? shape,
double? height,
Color? surfaceTintColor,
Color? shadowColor,
EdgeInsetsGeometry? padding,
}) {
return BottomAppBarTheme(
color: color ?? this.color,
elevation: elevation ?? this.elevation,
shape: shape ?? this.shape,
height: height ?? this.height,
surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor,
shadowColor: shadowColor ?? this.shadowColor,
padding: padding ?? this.padding,
);
}
/// Returns the closest [BottomAppBarThemeData] instance given the build context.
static BottomAppBarThemeData of(BuildContext context) {
final BottomAppBarTheme? bottomAppBarTheme =
context.dependOnInheritedWidgetOfExactType<BottomAppBarTheme>();
return bottomAppBarTheme?.data ?? Theme.of(context).bottomAppBarTheme;
}
/// Linearly interpolate between two bottom app bar themes.
///
/// {@macro dart.ui.shadow.lerp}
///
/// This method is obsolete and will be deprecated in a future release:
/// please use the [BottomAppBarThemeData.lerp] instead.
static BottomAppBarTheme lerp(BottomAppBarTheme? a, BottomAppBarTheme? b, double t) {
if (identical(a, b) && a != null) {
return a;
}
return BottomAppBarTheme(
color: Color.lerp(a?.color, b?.color, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t),
shape: t < 0.5 ? a?.shape : b?.shape,
height: lerpDouble(a?.height, b?.height, t),
surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t),
shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t),
);
}
@override
bool updateShouldNotify(BottomAppBarTheme oldWidget) => data != oldWidget.data;
@override
Widget wrap(BuildContext context, Widget child) {
return BottomAppBarTheme(data: data, child: child);
}
}
/// Defines default property values for descendant [BottomAppBar] widgets.
///
/// Descendant widgets obtain the current [BottomAppBarThemeData] object using
/// [BottomAppBarTheme.of]. Instances of [BottomAppBarThemeData] can be
/// customized with [BottomAppBarThemeData.copyWith].
///
/// Typically a [BottomAppBarThemeData] is specified as part of the overall [Theme]
/// with [ThemeData.bottomAppBarTheme].
///
/// All [BottomAppBarThemeData] properties are `null` by default. When null, the [BottomAppBar]
/// will use the values from [ThemeData] if they exist, otherwise it will
/// provide its own defaults. See the individual [BottomAppBar] properties for details.
///
/// See also:
///
/// * [BottomAppBar], which is the widget that this theme configures.
/// * [ThemeData], which describes the overall theme information for the
/// application.
@immutable
class BottomAppBarThemeData with Diagnosticable {
/// Creates a bottom app bar theme that can be used with [ThemeData.bottomAppBarTheme].
const BottomAppBarThemeData({
this.color, this.color,
this.elevation, this.elevation,
this.shape, this.shape,
@ -69,7 +252,7 @@ class BottomAppBarTheme with Diagnosticable {
/// Creates a copy of this object but with the given fields replaced with the /// Creates a copy of this object but with the given fields replaced with the
/// new values. /// new values.
BottomAppBarTheme copyWith({ BottomAppBarThemeData copyWith({
Color? color, Color? color,
double? elevation, double? elevation,
NotchedShape? shape, NotchedShape? shape,
@ -78,7 +261,7 @@ class BottomAppBarTheme with Diagnosticable {
Color? shadowColor, Color? shadowColor,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
}) { }) {
return BottomAppBarTheme( return BottomAppBarThemeData(
color: color ?? this.color, color: color ?? this.color,
elevation: elevation ?? this.elevation, elevation: elevation ?? this.elevation,
shape: shape ?? this.shape, shape: shape ?? this.shape,
@ -89,19 +272,14 @@ class BottomAppBarTheme with Diagnosticable {
); );
} }
/// The [ThemeData.bottomAppBarTheme] property of the ambient [Theme]. /// Linearly interpolate between two bottom app bar themes.
static BottomAppBarTheme of(BuildContext context) {
return Theme.of(context).bottomAppBarTheme;
}
/// Linearly interpolate between two BAB themes.
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static BottomAppBarTheme lerp(BottomAppBarTheme? a, BottomAppBarTheme? b, double t) { static BottomAppBarThemeData lerp(BottomAppBarThemeData? a, BottomAppBarThemeData? b, double t) {
if (identical(a, b) && a != null) { if (identical(a, b) && a != null) {
return a; return a;
} }
return BottomAppBarTheme( return BottomAppBarThemeData(
color: Color.lerp(a?.color, b?.color, t), color: Color.lerp(a?.color, b?.color, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t), elevation: lerpDouble(a?.elevation, b?.elevation, t),
shape: t < 0.5 ? a?.shape : b?.shape, shape: t < 0.5 ? a?.shape : b?.shape,
@ -124,7 +302,7 @@ class BottomAppBarTheme with Diagnosticable {
if (other.runtimeType != runtimeType) { if (other.runtimeType != runtimeType) {
return false; return false;
} }
return other is BottomAppBarTheme && return other is BottomAppBarThemeData &&
other.color == color && other.color == color &&
other.elevation == elevation && other.elevation == elevation &&
other.shape == shape && other.shape == shape &&
@ -138,11 +316,13 @@ class BottomAppBarTheme with Diagnosticable {
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(ColorProperty('color', color, defaultValue: null)); properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null)); properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
properties.add(DiagnosticsProperty<NotchedShape>('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty<NotchedShape?>('shape', shape, defaultValue: null));
properties.add(DiagnosticsProperty<double>('height', height, defaultValue: null)); properties.add(DoubleProperty('height', height, defaultValue: null));
properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null));
properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null)); properties.add(
DiagnosticsProperty<EdgeInsetsGeometry?>('padding', padding, defaultValue: null),
);
} }
} }

View File

@ -320,7 +320,8 @@ class ThemeData with Diagnosticable {
AppBarTheme? appBarTheme, AppBarTheme? appBarTheme,
BadgeThemeData? badgeTheme, BadgeThemeData? badgeTheme,
MaterialBannerThemeData? bannerTheme, MaterialBannerThemeData? bannerTheme,
BottomAppBarTheme? bottomAppBarTheme, // TODO(huycozy): Change the parameter type to BottomAppBarThemeData
Object? bottomAppBarTheme,
BottomNavigationBarThemeData? bottomNavigationBarTheme, BottomNavigationBarThemeData? bottomNavigationBarTheme,
BottomSheetThemeData? bottomSheetTheme, BottomSheetThemeData? bottomSheetTheme,
ButtonThemeData? buttonTheme, ButtonThemeData? buttonTheme,
@ -526,7 +527,16 @@ class ThemeData with Diagnosticable {
appBarTheme ??= const AppBarTheme(); appBarTheme ??= const AppBarTheme();
badgeTheme ??= const BadgeThemeData(); badgeTheme ??= const BadgeThemeData();
bannerTheme ??= const MaterialBannerThemeData(); bannerTheme ??= const MaterialBannerThemeData();
bottomAppBarTheme ??= const BottomAppBarTheme(); // TODO(huycozy): Clean this up once the type of `bottomAppBarTheme` is changed to `BottomAppBarThemeData`
if (bottomAppBarTheme != null) {
if (bottomAppBarTheme is BottomAppBarTheme) {
bottomAppBarTheme = bottomAppBarTheme.data;
} else if (bottomAppBarTheme is! BottomAppBarThemeData) {
throw ArgumentError(
'bottomAppBarTheme must be either a BottomAppBarThemeData or a BottomAppBarTheme',
);
}
}
bottomNavigationBarTheme ??= const BottomNavigationBarThemeData(); bottomNavigationBarTheme ??= const BottomNavigationBarThemeData();
bottomSheetTheme ??= const BottomSheetThemeData(); bottomSheetTheme ??= const BottomSheetThemeData();
cardTheme ??= const CardThemeData(); cardTheme ??= const CardThemeData();
@ -620,7 +630,9 @@ class ThemeData with Diagnosticable {
appBarTheme: appBarTheme, appBarTheme: appBarTheme,
badgeTheme: badgeTheme, badgeTheme: badgeTheme,
bannerTheme: bannerTheme, bannerTheme: bannerTheme,
bottomAppBarTheme: bottomAppBarTheme, // TODO(huycozy): Remove this type cast when bottomAppBarTheme is explicitly set to BottomAppBarThemeData
bottomAppBarTheme:
(bottomAppBarTheme as BottomAppBarThemeData?) ?? const BottomAppBarThemeData(),
bottomNavigationBarTheme: bottomNavigationBarTheme, bottomNavigationBarTheme: bottomNavigationBarTheme,
bottomSheetTheme: bottomSheetTheme, bottomSheetTheme: bottomSheetTheme,
buttonTheme: buttonTheme, buttonTheme: buttonTheme,
@ -1292,7 +1304,7 @@ class ThemeData with Diagnosticable {
final MaterialBannerThemeData bannerTheme; final MaterialBannerThemeData bannerTheme;
/// A theme for customizing the shape, elevation, and color of a [BottomAppBar]. /// A theme for customizing the shape, elevation, and color of a [BottomAppBar].
final BottomAppBarTheme bottomAppBarTheme; final BottomAppBarThemeData bottomAppBarTheme;
/// A theme for customizing the appearance and layout of [BottomNavigationBar] /// A theme for customizing the appearance and layout of [BottomNavigationBar]
/// widgets. /// widgets.
@ -1519,7 +1531,8 @@ class ThemeData with Diagnosticable {
AppBarTheme? appBarTheme, AppBarTheme? appBarTheme,
BadgeThemeData? badgeTheme, BadgeThemeData? badgeTheme,
MaterialBannerThemeData? bannerTheme, MaterialBannerThemeData? bannerTheme,
BottomAppBarTheme? bottomAppBarTheme, // TODO(huycozy): Change the parameter type to BottomAppBarThemeData
Object? bottomAppBarTheme,
BottomNavigationBarThemeData? bottomNavigationBarTheme, BottomNavigationBarThemeData? bottomNavigationBarTheme,
BottomSheetThemeData? bottomSheetTheme, BottomSheetThemeData? bottomSheetTheme,
ButtonThemeData? buttonTheme, ButtonThemeData? buttonTheme,
@ -1638,7 +1651,19 @@ class ThemeData with Diagnosticable {
appBarTheme: appBarTheme ?? this.appBarTheme, appBarTheme: appBarTheme ?? this.appBarTheme,
badgeTheme: badgeTheme ?? this.badgeTheme, badgeTheme: badgeTheme ?? this.badgeTheme,
bannerTheme: bannerTheme ?? this.bannerTheme, bannerTheme: bannerTheme ?? this.bannerTheme,
bottomAppBarTheme: bottomAppBarTheme ?? this.bottomAppBarTheme, // TODO(huycozy): Remove these checks when bottomAppBarTheme is a BottomAppBarThemeData
bottomAppBarTheme: () {
if (bottomAppBarTheme != null) {
if (bottomAppBarTheme is BottomAppBarTheme) {
return bottomAppBarTheme.data;
} else if (bottomAppBarTheme is! BottomAppBarThemeData) {
throw ArgumentError(
'bottomAppBarTheme must be either a BottomAppBarThemeData or a BottomAppBarTheme',
);
}
}
return bottomAppBarTheme as BottomAppBarThemeData? ?? this.bottomAppBarTheme;
}(),
bottomNavigationBarTheme: bottomNavigationBarTheme ?? this.bottomNavigationBarTheme, bottomNavigationBarTheme: bottomNavigationBarTheme ?? this.bottomNavigationBarTheme,
bottomSheetTheme: bottomSheetTheme ?? this.bottomSheetTheme, bottomSheetTheme: bottomSheetTheme ?? this.bottomSheetTheme,
buttonTheme: buttonTheme ?? this.buttonTheme, buttonTheme: buttonTheme ?? this.buttonTheme,
@ -1955,7 +1980,7 @@ class ThemeData with Diagnosticable {
appBarTheme: AppBarTheme.lerp(a.appBarTheme, b.appBarTheme, t), appBarTheme: AppBarTheme.lerp(a.appBarTheme, b.appBarTheme, t),
badgeTheme: BadgeThemeData.lerp(a.badgeTheme, b.badgeTheme, t), badgeTheme: BadgeThemeData.lerp(a.badgeTheme, b.badgeTheme, t),
bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t), bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t),
bottomAppBarTheme: BottomAppBarTheme.lerp(a.bottomAppBarTheme, b.bottomAppBarTheme, t), bottomAppBarTheme: BottomAppBarThemeData.lerp(a.bottomAppBarTheme, b.bottomAppBarTheme, t),
bottomNavigationBarTheme: BottomNavigationBarThemeData.lerp( bottomNavigationBarTheme: BottomNavigationBarThemeData.lerp(
a.bottomNavigationBarTheme, a.bottomNavigationBarTheme,
b.bottomNavigationBarTheme, b.bottomNavigationBarTheme,
@ -2036,7 +2061,6 @@ class ThemeData with Diagnosticable {
// order in every place that they are separated by section comments (e.g. // order in every place that they are separated by section comments (e.g.
// GENERAL CONFIGURATION). Each section except for deprecations should be // GENERAL CONFIGURATION). Each section except for deprecations should be
// alphabetical by symbol name. // alphabetical by symbol name.
// GENERAL CONFIGURATION
mapEquals(other.adaptationMap, adaptationMap) && mapEquals(other.adaptationMap, adaptationMap) &&
other.applyElevationOverlayColor == applyElevationOverlayColor && other.applyElevationOverlayColor == applyElevationOverlayColor &&
other.cupertinoOverrideTheme == cupertinoOverrideTheme && other.cupertinoOverrideTheme == cupertinoOverrideTheme &&
@ -2529,7 +2553,7 @@ class ThemeData with Diagnosticable {
), ),
); );
properties.add( properties.add(
DiagnosticsProperty<BottomAppBarTheme>( DiagnosticsProperty<BottomAppBarThemeData>(
'bottomAppBarTheme', 'bottomAppBarTheme',
bottomAppBarTheme, bottomAppBarTheme,
defaultValue: defaultData.bottomAppBarTheme, defaultValue: defaultData.bottomAppBarTheme,

View File

@ -205,7 +205,7 @@ void main() {
return Theme( return Theme(
data: Theme.of( data: Theme.of(
context, context,
).copyWith(bottomAppBarTheme: const BottomAppBarTheme(color: Color(0xffffff00))), ).copyWith(bottomAppBarTheme: const BottomAppBarThemeData(color: Color(0xffffff00))),
child: const Scaffold( child: const Scaffold(
floatingActionButton: FloatingActionButton(onPressed: null), floatingActionButton: FloatingActionButton(onPressed: null),
bottomNavigationBar: BottomAppBar(), bottomNavigationBar: BottomAppBar(),
@ -230,7 +230,7 @@ void main() {
return Theme( return Theme(
data: Theme.of( data: Theme.of(
context, context,
).copyWith(bottomAppBarTheme: const BottomAppBarTheme(color: Color(0xffffff00))), ).copyWith(bottomAppBarTheme: const BottomAppBarThemeData(color: Color(0xffffff00))),
child: const Scaffold( child: const Scaffold(
floatingActionButton: FloatingActionButton(onPressed: null), floatingActionButton: FloatingActionButton(onPressed: null),
bottomNavigationBar: BottomAppBar(color: Color(0xff0000ff)), bottomNavigationBar: BottomAppBar(color: Color(0xff0000ff)),
@ -251,7 +251,7 @@ void main() {
testWidgets('Material3 - Color overrides theme color', (WidgetTester tester) async { testWidgets('Material3 - Color overrides theme color', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(bottomAppBarTheme: const BottomAppBarTheme(color: Color(0xffffff00))), theme: ThemeData(bottomAppBarTheme: const BottomAppBarThemeData(color: Color(0xffffff00))),
home: Builder( home: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
return const Scaffold( return const Scaffold(

View File

@ -7,22 +7,133 @@
@Tags(<String>['reduced-test-set']) @Tags(<String>['reduced-test-set'])
library; library;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
test('BottomAppBarTheme lerp special cases', () { test('BottomAppBarThemeData copyWith, ==, hashCode, defaults', () {
expect(BottomAppBarTheme.lerp(null, null, 0), const BottomAppBarTheme()); expect(const BottomAppBarThemeData(), const BottomAppBarThemeData().copyWith());
const BottomAppBarTheme data = BottomAppBarTheme(); expect(
expect(identical(BottomAppBarTheme.lerp(data, data, 0.5), data), true); const BottomAppBarThemeData().hashCode,
const BottomAppBarThemeData().copyWith().hashCode,
);
expect(const BottomAppBarThemeData().color, null);
expect(const BottomAppBarThemeData().elevation, null);
expect(const BottomAppBarThemeData().shadowColor, null);
expect(const BottomAppBarThemeData().shape, null);
expect(const BottomAppBarThemeData().height, null);
expect(const BottomAppBarThemeData().surfaceTintColor, null);
expect(const BottomAppBarThemeData().padding, null);
});
test('BottomAppBarThemeData lerp special cases', () {
const BottomAppBarThemeData theme = BottomAppBarThemeData();
expect(identical(BottomAppBarThemeData.lerp(theme, theme, 0.5), theme), true);
});
testWidgets('Default BottomAppBarThemeData debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const BottomAppBarThemeData().debugFillProperties(builder);
final List<String> description =
builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
testWidgets('BottomAppBarThemeData implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const BottomAppBarThemeData(
color: Color(0xffff0000),
elevation: 1.0,
shape: CircularNotchedRectangle(),
height: 1.0,
shadowColor: Color(0xff0000ff),
surfaceTintColor: Color(0xff00ff00),
padding: EdgeInsets.all(8),
).debugFillProperties(builder);
final List<String> description =
builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[
'color: ${const Color(0xffff0000)}',
'elevation: 1.0',
"shape: Instance of 'CircularNotchedRectangle'",
'height: 1.0',
'surfaceTintColor: ${const Color(0xff00ff00)}',
'shadowColor: ${const Color(0xff0000ff)}',
'padding: EdgeInsets.all(8.0)',
]);
});
testWidgets('Local BottomAppBarTheme overrides defaults', (WidgetTester tester) async {
const Color color = Colors.blueAccent;
const double elevation = 1.0;
const Color shadowColor = Colors.black87;
const double height = 100.0;
const Color surfaceTintColor = Colors.transparent;
const NotchedShape shape = CircularNotchedRectangle();
const EdgeInsetsGeometry padding = EdgeInsets.all(8);
const BottomAppBarThemeData themeData = BottomAppBarThemeData(
color: color,
elevation: elevation,
shadowColor: shadowColor,
shape: shape,
height: height,
surfaceTintColor: surfaceTintColor,
padding: padding,
);
await tester.pumpWidget(_withTheme(localBABTheme: themeData));
final PhysicalShape widget = _getBabRenderObject(tester);
expect(widget.color, themeData.color);
expect(widget.elevation, themeData.elevation);
expect(widget.shadowColor, themeData.shadowColor);
final RenderBox renderBox = tester.renderObject<RenderBox>(find.byType(BottomAppBar));
expect(renderBox.size.height, themeData.height);
final bool hasFab =
Scaffold.of(tester.element(find.byType(BottomAppBar))).hasFloatingActionButton;
if (hasFab) {
expect(widget.clipper.toString(), '_BottomAppBarClipper');
} else {
expect(widget.clipper, isA<ShapeBorderClipper>());
final ShapeBorderClipper clipper = widget.clipper as ShapeBorderClipper;
expect(clipper.shape, isA<RoundedRectangleBorder>());
}
final Color effectiveColor = ElevationOverlay.applySurfaceTint(
themeData.color!,
themeData.surfaceTintColor,
themeData.elevation!,
);
expect(widget.color, effectiveColor);
// The BottomAppBar has two Padding widgets in its hierarchy:
// 1. The first Padding is from the SafeArea widget.
// 2. The second Padding is the one that applies the theme's padding.
final Padding paddingWidget = tester.widget<Padding>(
find.descendant(of: find.byType(BottomAppBar), matching: find.byType(Padding).at(1)),
);
expect(paddingWidget.padding, padding);
}); });
group('Material 2 tests', () { group('Material 2 tests', () {
testWidgets('Material2 - BAB theme overrides color', (WidgetTester tester) async { testWidgets('Material2 - BAB theme overrides color', (WidgetTester tester) async {
const Color themedColor = Colors.black87; const Color themedColor = Colors.black87;
const BottomAppBarTheme theme = BottomAppBarTheme(color: themedColor); const BottomAppBarThemeData theme = BottomAppBarThemeData(color: themedColor);
await tester.pumpWidget(_withTheme(theme, useMaterial3: false)); await tester.pumpWidget(_withTheme(babTheme: theme, useMaterial3: false));
final PhysicalShape widget = _getBabRenderObject(tester); final PhysicalShape widget = _getBabRenderObject(tester);
expect(widget.color, themedColor); expect(widget.color, themedColor);
@ -31,7 +142,7 @@ void main() {
testWidgets('Material2 - BAB color - Widget', (WidgetTester tester) async { testWidgets('Material2 - BAB color - Widget', (WidgetTester tester) async {
const Color babThemeColor = Colors.black87; const Color babThemeColor = Colors.black87;
const Color babColor = Colors.pink; const Color babColor = Colors.pink;
const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); const BottomAppBarThemeData theme = BottomAppBarThemeData(color: babThemeColor);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
@ -46,7 +157,7 @@ void main() {
testWidgets('Material2 - BAB color - BabTheme', (WidgetTester tester) async { testWidgets('Material2 - BAB color - BabTheme', (WidgetTester tester) async {
const Color babThemeColor = Colors.black87; const Color babThemeColor = Colors.black87;
const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); const BottomAppBarThemeData theme = BottomAppBarThemeData(color: babThemeColor);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
@ -66,7 +177,7 @@ void main() {
MaterialApp( MaterialApp(
theme: ThemeData( theme: ThemeData(
useMaterial3: false, useMaterial3: false,
bottomAppBarTheme: const BottomAppBarTheme(color: themeColor), bottomAppBarTheme: const BottomAppBarThemeData(color: themeColor),
), ),
home: const Scaffold(body: BottomAppBar()), home: const Scaffold(body: BottomAppBar()),
), ),
@ -90,13 +201,13 @@ void main() {
}); });
testWidgets('Material2 - BAB theme customizes shape', (WidgetTester tester) async { testWidgets('Material2 - BAB theme customizes shape', (WidgetTester tester) async {
const BottomAppBarTheme theme = BottomAppBarTheme( const BottomAppBarThemeData theme = BottomAppBarThemeData(
color: Colors.white30, color: Colors.white30,
shape: CircularNotchedRectangle(), shape: CircularNotchedRectangle(),
elevation: 1.0, elevation: 1.0,
); );
await tester.pumpWidget(_withTheme(theme, useMaterial3: false)); await tester.pumpWidget(_withTheme(babTheme: theme, useMaterial3: false));
await expectLater( await expectLater(
find.byKey(_painterKey), find.byKey(_painterKey),
@ -122,8 +233,8 @@ void main() {
group('Material 3 tests', () { group('Material 3 tests', () {
testWidgets('Material3 - BAB theme overrides color', (WidgetTester tester) async { testWidgets('Material3 - BAB theme overrides color', (WidgetTester tester) async {
const Color themedColor = Colors.black87; const Color themedColor = Colors.black87;
const BottomAppBarTheme theme = BottomAppBarTheme(color: themedColor, elevation: 0); const BottomAppBarThemeData theme = BottomAppBarThemeData(color: themedColor, elevation: 0);
await tester.pumpWidget(_withTheme(theme, useMaterial3: true)); await tester.pumpWidget(_withTheme(babTheme: theme));
final PhysicalShape widget = _getBabRenderObject(tester); final PhysicalShape widget = _getBabRenderObject(tester);
expect(widget.color, themedColor); expect(widget.color, themedColor);
@ -132,7 +243,7 @@ void main() {
testWidgets('Material3 - BAB color - Widget', (WidgetTester tester) async { testWidgets('Material3 - BAB color - Widget', (WidgetTester tester) async {
const Color babThemeColor = Colors.black87; const Color babThemeColor = Colors.black87;
const Color babColor = Colors.pink; const Color babColor = Colors.pink;
const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); const BottomAppBarThemeData theme = BottomAppBarThemeData(color: babThemeColor);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
@ -149,7 +260,7 @@ void main() {
testWidgets('Material3 - BAB color - BabTheme', (WidgetTester tester) async { testWidgets('Material3 - BAB color - BabTheme', (WidgetTester tester) async {
const Color babThemeColor = Colors.black87; const Color babThemeColor = Colors.black87;
const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); const BottomAppBarThemeData theme = BottomAppBarThemeData(color: babThemeColor);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
@ -180,12 +291,12 @@ void main() {
testWidgets('Material3 - BAB theme overrides surfaceTintColor', (WidgetTester tester) async { testWidgets('Material3 - BAB theme overrides surfaceTintColor', (WidgetTester tester) async {
const Color color = Colors.blue; // base color that the surface tint will be applied to const Color color = Colors.blue; // base color that the surface tint will be applied to
const Color babThemeSurfaceTintColor = Colors.black87; const Color babThemeSurfaceTintColor = Colors.black87;
const BottomAppBarTheme theme = BottomAppBarTheme( const BottomAppBarThemeData theme = BottomAppBarThemeData(
color: color, color: color,
surfaceTintColor: babThemeSurfaceTintColor, surfaceTintColor: babThemeSurfaceTintColor,
elevation: 0, elevation: 0,
); );
await tester.pumpWidget(_withTheme(theme, useMaterial3: true)); await tester.pumpWidget(_withTheme(babTheme: theme));
final PhysicalShape widget = _getBabRenderObject(tester); final PhysicalShape widget = _getBabRenderObject(tester);
expect(widget.color, ElevationOverlay.applySurfaceTint(color, babThemeSurfaceTintColor, 0)); expect(widget.color, ElevationOverlay.applySurfaceTint(color, babThemeSurfaceTintColor, 0));
@ -193,11 +304,11 @@ void main() {
testWidgets('Material3 - BAB theme overrides shadowColor', (WidgetTester tester) async { testWidgets('Material3 - BAB theme overrides shadowColor', (WidgetTester tester) async {
const Color babThemeShadowColor = Colors.yellow; const Color babThemeShadowColor = Colors.yellow;
const BottomAppBarTheme theme = BottomAppBarTheme( const BottomAppBarThemeData theme = BottomAppBarThemeData(
shadowColor: babThemeShadowColor, shadowColor: babThemeShadowColor,
elevation: 0, elevation: 0,
); );
await tester.pumpWidget(_withTheme(theme, useMaterial3: true)); await tester.pumpWidget(_withTheme(babTheme: theme));
final PhysicalShape widget = _getBabRenderObject(tester); final PhysicalShape widget = _getBabRenderObject(tester);
expect(widget.shadowColor, babThemeShadowColor); expect(widget.shadowColor, babThemeShadowColor);
@ -207,7 +318,9 @@ void main() {
const Color color = Colors.white10; // base color that the surface tint will be applied to const Color color = Colors.white10; // base color that the surface tint will be applied to
const Color babThemeSurfaceTintColor = Colors.black87; const Color babThemeSurfaceTintColor = Colors.black87;
const Color babSurfaceTintColor = Colors.pink; const Color babSurfaceTintColor = Colors.pink;
const BottomAppBarTheme theme = BottomAppBarTheme(surfaceTintColor: babThemeSurfaceTintColor); const BottomAppBarThemeData theme = BottomAppBarThemeData(
surfaceTintColor: babThemeSurfaceTintColor,
);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(bottomAppBarTheme: theme), theme: ThemeData(bottomAppBarTheme: theme),
@ -224,7 +337,7 @@ void main() {
testWidgets('Material3 - BAB surfaceTintColor - BabTheme', (WidgetTester tester) async { testWidgets('Material3 - BAB surfaceTintColor - BabTheme', (WidgetTester tester) async {
const Color color = Colors.blue; // base color that the surface tint will be applied to const Color color = Colors.blue; // base color that the surface tint will be applied to
const Color babThemeColor = Colors.black87; const Color babThemeColor = Colors.black87;
const BottomAppBarTheme theme = BottomAppBarTheme(surfaceTintColor: babThemeColor); const BottomAppBarThemeData theme = BottomAppBarThemeData(surfaceTintColor: babThemeColor);
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
@ -247,20 +360,23 @@ PhysicalShape _getBabRenderObject(WidgetTester tester) {
final Key _painterKey = UniqueKey(); final Key _painterKey = UniqueKey();
Widget _withTheme(BottomAppBarTheme theme, {required bool useMaterial3}) { Widget _withTheme({
BottomAppBarThemeData? babTheme,
BottomAppBarThemeData? localBABTheme,
bool useMaterial3 = true,
}) {
Widget babWidget = const BottomAppBar(
child: Row(children: <Widget>[Icon(Icons.add), Expanded(child: SizedBox()), Icon(Icons.add)]),
);
if (localBABTheme != null) {
babWidget = BottomAppBarTheme(data: localBABTheme, child: babWidget);
}
return MaterialApp( return MaterialApp(
theme: ThemeData(useMaterial3: useMaterial3, bottomAppBarTheme: theme), theme: ThemeData(useMaterial3: useMaterial3, bottomAppBarTheme: babTheme),
home: Scaffold( home: Scaffold(
floatingActionButton: const FloatingActionButton(onPressed: null), floatingActionButton: const FloatingActionButton(onPressed: null),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: RepaintBoundary( bottomNavigationBar: RepaintBoundary(key: _painterKey, child: babWidget),
key: _painterKey,
child: const BottomAppBar(
child: Row(
children: <Widget>[Icon(Icons.add), Expanded(child: SizedBox()), Icon(Icons.add)],
),
),
),
), ),
); );
} }

View File

@ -1332,7 +1332,7 @@ void main() {
appBarTheme: const AppBarTheme(backgroundColor: Colors.black), appBarTheme: const AppBarTheme(backgroundColor: Colors.black),
badgeTheme: const BadgeThemeData(backgroundColor: Colors.black), badgeTheme: const BadgeThemeData(backgroundColor: Colors.black),
bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.black), bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.black),
bottomAppBarTheme: const BottomAppBarTheme(color: Colors.black), bottomAppBarTheme: const BottomAppBarThemeData(color: Colors.black),
bottomNavigationBarTheme: const BottomNavigationBarThemeData( bottomNavigationBarTheme: const BottomNavigationBarThemeData(
type: BottomNavigationBarType.fixed, type: BottomNavigationBarType.fixed,
), ),
@ -1461,7 +1461,7 @@ void main() {
appBarTheme: const AppBarTheme(backgroundColor: Colors.white), appBarTheme: const AppBarTheme(backgroundColor: Colors.white),
badgeTheme: const BadgeThemeData(backgroundColor: Colors.black), badgeTheme: const BadgeThemeData(backgroundColor: Colors.black),
bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.white), bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.white),
bottomAppBarTheme: const BottomAppBarTheme(color: Colors.white), bottomAppBarTheme: const BottomAppBarThemeData(color: Colors.white),
bottomNavigationBarTheme: const BottomNavigationBarThemeData( bottomNavigationBarTheme: const BottomNavigationBarThemeData(
type: BottomNavigationBarType.shifting, type: BottomNavigationBarType.shifting,
), ),