diff --git a/packages/flutter/lib/src/material/bottom_app_bar.dart b/packages/flutter/lib/src/material/bottom_app_bar.dart index 9c9dab4810..758f63bedf 100644 --- a/packages/flutter/lib/src/material/bottom_app_bar.dart +++ b/packages/flutter/lib/src/material/bottom_app_bar.dart @@ -69,6 +69,7 @@ class BottomAppBar extends StatefulWidget { this.clipBehavior = Clip.none, this.notchMargin = 4.0, this.child, + this.padding, this.surfaceTintColor, this.height, }) : assert(elevation == null || elevation >= 0.0), @@ -83,6 +84,12 @@ class BottomAppBar extends StatefulWidget { /// being an [IconButton] with the [Icons.menu] icon. final Widget? child; + /// The amount of space to surround the child inside the bounds of the [BottomAppBar]. + /// + /// In Material 3 the padding will default to `EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0)` + /// Otherwise the value will default to EdgeInsets.zero. + final EdgeInsetsGeometry? padding; + /// The bottom app bar's background color. /// /// If this property is null then [BottomAppBarTheme.color] of @@ -173,10 +180,10 @@ class _BottomAppBarState extends State { final Color surfaceTintColor = widget.surfaceTintColor ?? babTheme.surfaceTintColor ?? defaults.surfaceTintColor!; final Color effectiveColor = isMaterial3 ? color : ElevationOverlay.applyOverlay(context, color, elevation); - final Widget? child = isMaterial3 ? Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0), + final Widget child = Padding( + padding: widget.padding ?? babTheme.padding ?? (isMaterial3 ? const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0) : EdgeInsets.zero), child: widget.child, - ) : widget.child; + ); return SizedBox( height: height, diff --git a/packages/flutter/lib/src/material/bottom_app_bar_theme.dart b/packages/flutter/lib/src/material/bottom_app_bar_theme.dart index fae3cbc4c0..0b6063a7ca 100644 --- a/packages/flutter/lib/src/material/bottom_app_bar_theme.dart +++ b/packages/flutter/lib/src/material/bottom_app_bar_theme.dart @@ -34,31 +34,35 @@ class BottomAppBarTheme with Diagnosticable { this.shape, this.height, this.surfaceTintColor, + this.padding, }); - /// Default value for [BottomAppBar.color]. + /// Overrides the default value for [BottomAppBar.color]. /// /// If null, [BottomAppBar] uses [ThemeData.bottomAppBarColor]. final Color? color; - /// Default value for [BottomAppBar.elevation]. + /// Overrides the default value for [BottomAppBar.elevation]. final double? elevation; - /// Default value for [BottomAppBar.shape]. + /// Overrides the default value for [BottomAppBar.shape]. final NotchedShape? shape; - /// Default value for [BottomAppBar.height]. + /// Overrides the default value for [BottomAppBar.height]. /// /// If null, [BottomAppBar] height will be the minimum on the non material 3. final double? height; - /// Default value for [BottomAppBar.surfaceTintColor]. + /// Overrides the default value for [BottomAppBar.surfaceTintColor]. /// /// If null, [BottomAppBar] will not display an overlay color. /// /// See [Material.surfaceTintColor] for more details. final Color? surfaceTintColor; + /// Overrides the default value for [BottomAppBar.padding]. + final EdgeInsetsGeometry? padding; + /// Creates a copy of this object but with the given fields replaced with the /// new values. BottomAppBarTheme copyWith({ @@ -67,6 +71,7 @@ class BottomAppBarTheme with Diagnosticable { NotchedShape? shape, double? height, Color? surfaceTintColor, + EdgeInsetsGeometry? padding, }) { return BottomAppBarTheme( color: color ?? this.color, @@ -74,6 +79,7 @@ class BottomAppBarTheme with Diagnosticable { shape: shape ?? this.shape, height: height ?? this.height, surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, + padding: padding ?? this.padding, ); } @@ -94,7 +100,8 @@ class BottomAppBarTheme with Diagnosticable { 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?.color, b?.color, t), + surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), + padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t), ); } @@ -105,6 +112,7 @@ class BottomAppBarTheme with Diagnosticable { shape, height, surfaceTintColor, + padding, ); @override @@ -120,7 +128,8 @@ class BottomAppBarTheme with Diagnosticable { && other.elevation == elevation && other.shape == shape && other.height == height - && other.surfaceTintColor == surfaceTintColor; + && other.surfaceTintColor == surfaceTintColor + && other.padding == padding; } @override @@ -131,5 +140,6 @@ class BottomAppBarTheme with Diagnosticable { properties.add(DiagnosticsProperty('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty('height', height, defaultValue: null)); properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); + properties.add(DiagnosticsProperty('padding', padding, defaultValue: null)); } } diff --git a/packages/flutter/test/material/bottom_app_bar_test.dart b/packages/flutter/test/material/bottom_app_bar_test.dart index 9885765bd1..fd04ad5727 100644 --- a/packages/flutter/test/material/bottom_app_bar_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_test.dart @@ -85,6 +85,71 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44572 + + testWidgets('Custom Padding', (WidgetTester tester) async { + const EdgeInsets customPadding = EdgeInsets.all(10); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.from(colorScheme: const ColorScheme.light()), + home: Builder( + builder: (BuildContext context) { + return const Scaffold( + body: Align( + alignment: Alignment.bottomCenter, + child: BottomAppBar( + padding: customPadding, + child:ColoredBox( + color:Colors.green, + child:SizedBox(width: 300, height: 60), + ), + ), + ), + ); + }, + ), + ), + ); + + final BottomAppBar bottomAppBar = tester.widget(find.byType(BottomAppBar)); + expect(bottomAppBar.padding, customPadding); + final Rect babRect = tester.getRect(find.byType(BottomAppBar)); + final Rect childRect = tester.getRect(find.byType(ColoredBox)); + expect(childRect, const Rect.fromLTRB(250, 530, 550, 590)); + expect(babRect, const Rect.fromLTRB(240, 520, 560, 600)); + }); + + testWidgets('Custom Padding in Material 3', (WidgetTester tester) async { + const EdgeInsets customPadding = EdgeInsets.all(10); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true), + home: Builder( + builder: (BuildContext context) { + return const Scaffold( + body: Align( + alignment: Alignment.bottomCenter, + child: BottomAppBar( + padding: customPadding, + child:ColoredBox( + color:Colors.green, + child:SizedBox(width: 300, height: 60), + ), + ), + ), + ); + }, + ), + ), + ); + + final BottomAppBar bottomAppBar = tester.widget(find.byType(BottomAppBar)); + expect(bottomAppBar.padding, customPadding); + final Rect babRect = tester.getRect(find.byType(BottomAppBar)); + final Rect childRect = tester.getRect(find.byType(ColoredBox)); + expect(childRect, const Rect.fromLTRB(250, 530, 550, 590)); + expect(babRect, const Rect.fromLTRB(240, 520, 560, 600)); + }); + testWidgets('color defaults to Theme.bottomAppBarColor', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp(