From 7abb083ae2ad9f28172f53899ec7757521dfb2bf Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 8 Nov 2024 16:19:18 +0200 Subject: [PATCH] Add ability to override `NavigationDestination.label` padding for `NavigationBar` (#158260) Fixes [Long NavigationBar tab titles can't be padded from the sides of the screen](https://github.com/flutter/flutter/issues/158130) ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( navigationBarTheme: const NavigationBarThemeData( labelTextStyle: WidgetStatePropertyAll(TextStyle(overflow: TextOverflow.ellipsis)), labelPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 4), )), home: Scaffold( body: Center( child: Text( 'Custom NavigationBar label padding', style: Theme.of(context).textTheme.titleMedium, ), ), bottomNavigationBar: NavigationBar( destinations: const [ NavigationDestination( icon: Icon(Icons.favorite_rounded), label: 'Long Label Text', ), NavigationDestination( // icon: SizedBox.shrink(), icon: Icon(Icons.favorite_rounded), label: 'Long Label Text', ), NavigationDestination( icon: Icon(Icons.favorite_rounded), label: 'Long Label Text', ), ], ), ), ); } } ```
### Default `NavigationDestination.label` padding with long label Screenshot 2024-11-06 at 14 30 52 ### Custom `NavigationDestination.label` padding with long label Screenshot 2024-11-06 at 14 32 02 --- .../lib/navigation_bar_template.dart | 35 +++++--- .../lib/src/material/navigation_bar.dart | 86 +++++++++++++------ .../src/material/navigation_bar_theme.dart | 12 ++- .../test/material/navigation_bar_test.dart | 74 ++++++++++++++++ .../material/navigation_bar_theme_test.dart | 52 ++++++++--- 5 files changed, 207 insertions(+), 52 deletions(-) diff --git a/dev/tools/gen_defaults/lib/navigation_bar_template.dart b/dev/tools/gen_defaults/lib/navigation_bar_template.dart index 55d0392c0c4f4..65d2a21551d47 100644 --- a/dev/tools/gen_defaults/lib/navigation_bar_template.dart +++ b/dev/tools/gen_defaults/lib/navigation_bar_template.dart @@ -14,23 +14,27 @@ class NavigationBarTemplate extends TokenTemplate { String generate() => ''' class _${blockName}DefaultsM3 extends NavigationBarThemeData { _${blockName}DefaultsM3(this.context) - : super( - height: ${getToken("md.comp.navigation-bar.container.height")}, - elevation: ${elevation("md.comp.navigation-bar.container")}, - labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, - ); + : super( + height: ${getToken("md.comp.navigation-bar.container.height")}, + elevation: ${elevation("md.comp.navigation-bar.container")}, + labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, + ); final BuildContext context; late final ColorScheme _colors = Theme.of(context).colorScheme; late final TextTheme _textTheme = Theme.of(context).textTheme; - @override Color? get backgroundColor => ${componentColor("md.comp.navigation-bar.container")}; + @override + Color? get backgroundColor => ${componentColor("md.comp.navigation-bar.container")}; - @override Color? get shadowColor => ${colorOrTransparent("md.comp.navigation-bar.container.shadow-color")}; + @override + Color? get shadowColor => ${colorOrTransparent("md.comp.navigation-bar.container.shadow-color")}; - @override Color? get surfaceTintColor => ${colorOrTransparent("md.comp.navigation-bar.container.surface-tint-layer.color")}; + @override + Color? get surfaceTintColor => ${colorOrTransparent("md.comp.navigation-bar.container.surface-tint-layer.color")}; - @override MaterialStateProperty? get iconTheme { + @override + MaterialStateProperty? get iconTheme { return MaterialStateProperty.resolveWith((Set states) { return IconThemeData( size: ${getToken("md.comp.navigation-bar.icon.size")}, @@ -43,10 +47,14 @@ class _${blockName}DefaultsM3 extends NavigationBarThemeData { }); } - @override Color? get indicatorColor => ${componentColor("md.comp.navigation-bar.active-indicator")}; - @override ShapeBorder? get indicatorShape => ${shape("md.comp.navigation-bar.active-indicator")}; + @override + Color? get indicatorColor => ${componentColor("md.comp.navigation-bar.active-indicator")}; - @override MaterialStateProperty? get labelTextStyle { + @override + ShapeBorder? get indicatorShape => ${shape("md.comp.navigation-bar.active-indicator")}; + + @override + MaterialStateProperty? get labelTextStyle { return MaterialStateProperty.resolveWith((Set states) { final TextStyle style = ${textStyle("md.comp.navigation-bar.label-text")}!; return style.apply( @@ -58,6 +66,9 @@ class _${blockName}DefaultsM3 extends NavigationBarThemeData { ); }); } + + @override + EdgeInsetsGeometry? get labelPadding => const EdgeInsets.only(top: 4); } '''; } diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index e6490962516a6..5c1311f1632a8 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -111,6 +111,7 @@ class NavigationBar extends StatelessWidget { this.height, this.labelBehavior, this.overlayColor, + this.labelPadding, }) : assert(destinations.length >= 2), assert(0 <= selectedIndex && selectedIndex < destinations.length); @@ -223,6 +224,13 @@ class NavigationBar extends StatelessWidget { /// the [NavigationDestination] is focused, hovered, or pressed. final MaterialStateProperty? overlayColor; + /// The padding around the [NavigationDestination.label] widget. + /// + /// When [labelPadding] is null, [NavigationBarThemeData.labelPadding] + /// is used. If that is also null, the default padding is 4 pixels on + /// the top. + final EdgeInsetsGeometry? labelPadding; + VoidCallback _handleTap(int index) { return onDestinationSelected != null ? () => onDestinationSelected!(index) @@ -267,6 +275,7 @@ class NavigationBar extends StatelessWidget { indicatorShape: indicatorShape, overlayColor: overlayColor, onTap: _handleTap(i), + labelPadding: labelPadding, child: destinations[i], ); }, @@ -423,6 +432,9 @@ class NavigationDestination extends StatelessWidget { ?? defaults.labelTextStyle!.resolve(unselectedState); final TextStyle? effectiveDisabledLabelTextStyle = navigationBarTheme.labelTextStyle?.resolve(disabledState) ?? defaults.labelTextStyle!.resolve(disabledState); + final EdgeInsetsGeometry labelPadding = info.labelPadding + ?? navigationBarTheme.labelPadding + ?? defaults.labelPadding!; final TextStyle? textStyle = enabled ? animation.isForwardOrCompleted @@ -431,7 +443,7 @@ class NavigationDestination extends StatelessWidget { : effectiveDisabledLabelTextStyle; return Padding( - padding: const EdgeInsets.only(top: 4), + padding: labelPadding, child: MediaQuery.withClampedTextScaling( // Set maximum text scale factor to _kMaxLabelTextScaleFactor for the // label to keep the visual hierarchy the same even with larger font @@ -592,6 +604,7 @@ class _NavigationDestinationInfo extends InheritedWidget { required this.indicatorShape, required this.overlayColor, required this.onTap, + this.labelPadding, required super.child, }); @@ -669,6 +682,11 @@ class _NavigationDestinationInfo extends InheritedWidget { /// with [index] passed in. final VoidCallback onTap; + /// The padding around the [label] widget. + /// + /// Defaults to a padding of 4 pixels on the top. + final EdgeInsetsGeometry? labelPadding; + /// Returns a non null [_NavigationDestinationInfo]. /// /// This will return an error if called with no [_NavigationDestinationInfo] @@ -1313,32 +1331,39 @@ NavigationBarThemeData _defaultsFor(BuildContext context) { // Hand coded defaults based on Material Design 2. class _NavigationBarDefaultsM2 extends NavigationBarThemeData { _NavigationBarDefaultsM2(BuildContext context) - : _theme = Theme.of(context), - _colors = Theme.of(context).colorScheme, - super( - height: 80.0, - elevation: 0.0, - indicatorShape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))), - labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, - ); + : _theme = Theme.of(context), + _colors = Theme.of(context).colorScheme, + super( + height: 80.0, + elevation: 0.0, + indicatorShape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))), + labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, + ); final ThemeData _theme; final ColorScheme _colors; // With Material 2, the NavigationBar uses an overlay blend for the // default color regardless of light/dark mode. - @override Color? get backgroundColor => ElevationOverlay.colorWithOverlay(_colors.surface, _colors.onSurface, 3.0); + @override + Color? get backgroundColor => ElevationOverlay.colorWithOverlay(_colors.surface, _colors.onSurface, 3.0); - @override MaterialStateProperty? get iconTheme { + @override + MaterialStateProperty? get iconTheme { return MaterialStatePropertyAll(IconThemeData( size: 24, color: _colors.onSurface, )); } - @override Color? get indicatorColor => _colors.secondary.withOpacity(0.24); + @override + Color? get indicatorColor => _colors.secondary.withOpacity(0.24); + + @override + MaterialStateProperty? get labelTextStyle => MaterialStatePropertyAll(_theme.textTheme.labelSmall!.copyWith(color: _colors.onSurface)); - @override MaterialStateProperty? get labelTextStyle => MaterialStatePropertyAll(_theme.textTheme.labelSmall!.copyWith(color: _colors.onSurface)); + @override + EdgeInsetsGeometry? get labelPadding => const EdgeInsets.only(top: 4); } // BEGIN GENERATED TOKEN PROPERTIES - NavigationBar @@ -1350,23 +1375,27 @@ class _NavigationBarDefaultsM2 extends NavigationBarThemeData { class _NavigationBarDefaultsM3 extends NavigationBarThemeData { _NavigationBarDefaultsM3(this.context) - : super( - height: 80.0, - elevation: 3.0, - labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, - ); + : super( + height: 80.0, + elevation: 3.0, + labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, + ); final BuildContext context; late final ColorScheme _colors = Theme.of(context).colorScheme; late final TextTheme _textTheme = Theme.of(context).textTheme; - @override Color? get backgroundColor => _colors.surfaceContainer; + @override + Color? get backgroundColor => _colors.surfaceContainer; - @override Color? get shadowColor => Colors.transparent; + @override + Color? get shadowColor => Colors.transparent; - @override Color? get surfaceTintColor => Colors.transparent; + @override + Color? get surfaceTintColor => Colors.transparent; - @override MaterialStateProperty? get iconTheme { + @override + MaterialStateProperty? get iconTheme { return MaterialStateProperty.resolveWith((Set states) { return IconThemeData( size: 24.0, @@ -1379,10 +1408,14 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData { }); } - @override Color? get indicatorColor => _colors.secondaryContainer; - @override ShapeBorder? get indicatorShape => const StadiumBorder(); + @override + Color? get indicatorColor => _colors.secondaryContainer; + + @override + ShapeBorder? get indicatorShape => const StadiumBorder(); - @override MaterialStateProperty? get labelTextStyle { + @override + MaterialStateProperty? get labelTextStyle { return MaterialStateProperty.resolveWith((Set states) { final TextStyle style = _textTheme.labelMedium!; return style.apply( @@ -1394,6 +1427,9 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData { ); }); } + + @override + EdgeInsetsGeometry? get labelPadding => const EdgeInsets.only(top: 4); } // END GENERATED TOKEN PROPERTIES - NavigationBar diff --git a/packages/flutter/lib/src/material/navigation_bar_theme.dart b/packages/flutter/lib/src/material/navigation_bar_theme.dart index adb9e3985cec1..a36ce60f0816c 100644 --- a/packages/flutter/lib/src/material/navigation_bar_theme.dart +++ b/packages/flutter/lib/src/material/navigation_bar_theme.dart @@ -53,6 +53,7 @@ class NavigationBarThemeData with Diagnosticable { this.iconTheme, this.labelBehavior, this.overlayColor, + this.labelPadding, }); /// Overrides the default value of [NavigationBar.height]. @@ -95,6 +96,9 @@ class NavigationBarThemeData with Diagnosticable { /// Overrides the default value of [NavigationBar.overlayColor]. final MaterialStateProperty? overlayColor; + /// Overrides the default value of [NavigationBar.labelPadding]. + final EdgeInsetsGeometry? labelPadding; + /// Creates a copy of this object with the given fields replaced with the /// new values. NavigationBarThemeData copyWith({ @@ -109,6 +113,7 @@ class NavigationBarThemeData with Diagnosticable { MaterialStateProperty? iconTheme, NavigationDestinationLabelBehavior? labelBehavior, MaterialStateProperty? overlayColor, + EdgeInsetsGeometry? labelPadding, }) { return NavigationBarThemeData( height: height ?? this.height, @@ -122,6 +127,7 @@ class NavigationBarThemeData with Diagnosticable { iconTheme: iconTheme ?? this.iconTheme, labelBehavior: labelBehavior ?? this.labelBehavior, overlayColor: overlayColor ?? this.overlayColor, + labelPadding: labelPadding ?? this.labelPadding, ); } @@ -146,6 +152,7 @@ class NavigationBarThemeData with Diagnosticable { iconTheme: MaterialStateProperty.lerp(a?.iconTheme, b?.iconTheme, t, IconThemeData.lerp), labelBehavior: t < 0.5 ? a?.labelBehavior : b?.labelBehavior, overlayColor: MaterialStateProperty.lerp(a?.overlayColor, b?.overlayColor, t, Color.lerp), + labelPadding: EdgeInsetsGeometry.lerp(a?.labelPadding, b?.labelPadding, t), ); } @@ -162,6 +169,7 @@ class NavigationBarThemeData with Diagnosticable { iconTheme, labelBehavior, overlayColor, + labelPadding, ); @override @@ -183,7 +191,8 @@ class NavigationBarThemeData with Diagnosticable { && other.labelTextStyle == labelTextStyle && other.iconTheme == iconTheme && other.labelBehavior == labelBehavior - && other.overlayColor == overlayColor; + && other.overlayColor == overlayColor + && other.labelPadding == labelPadding; } @override @@ -200,6 +209,7 @@ class NavigationBarThemeData with Diagnosticable { properties.add(DiagnosticsProperty>('iconTheme', iconTheme, defaultValue: null)); properties.add(DiagnosticsProperty('labelBehavior', labelBehavior, defaultValue: null)); properties.add(DiagnosticsProperty>('overlayColor', overlayColor, defaultValue: null)); + properties.add(DiagnosticsProperty('labelPadding', labelPadding, defaultValue: null)); } } diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index 01ff1cb19f42c..02f7c6b17a692 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -1180,6 +1180,38 @@ void main() { ); }); + testWidgets('NavigationBar.labelPadding overrides NavigationDestination.label padding', (WidgetTester tester) async { + const EdgeInsetsGeometry labelPadding = EdgeInsets.all(8); + Widget buildNavigationBar({ EdgeInsetsGeometry? labelPadding }) { + return MaterialApp( + home: Scaffold( + bottomNavigationBar: NavigationBar( + labelPadding: labelPadding, + destinations: const [ + NavigationDestination( + icon: Icon(Icons.home), + label: 'Home', + ), + NavigationDestination( + icon: Icon(Icons.settings), + label: 'Settings', + ), + ], + onDestinationSelected: (int i) { }, + ), + ), + ); + } + + await tester.pumpWidget(buildNavigationBar()); + expect(_getLabelPadding(tester, 'Home'), const EdgeInsets.only(top: 4)); + expect(_getLabelPadding(tester, 'Settings'), const EdgeInsets.only(top: 4)); + + await tester.pumpWidget(buildNavigationBar(labelPadding: labelPadding)); + expect(_getLabelPadding(tester, 'Home'), labelPadding); + expect(_getLabelPadding(tester, 'Settings'), labelPadding); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests @@ -1533,6 +1565,39 @@ void main() { expect(icon.color, initialColor); }); }); + + testWidgets('NavigationBar.labelPadding overrides NavigationDestination.label padding', (WidgetTester tester) async { + const EdgeInsetsGeometry labelPadding = EdgeInsets.all(8); + Widget buildNavigationBar({ EdgeInsetsGeometry? labelPadding }) { + return MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + bottomNavigationBar: NavigationBar( + labelPadding: labelPadding, + destinations: const [ + NavigationDestination( + icon: Icon(Icons.home), + label: 'Home', + ), + NavigationDestination( + icon: Icon(Icons.settings), + label: 'Settings', + ), + ], + onDestinationSelected: (int i) { }, + ), + ), + ); + } + + await tester.pumpWidget(buildNavigationBar()); + expect(_getLabelPadding(tester, 'Home'), const EdgeInsets.only(top: 4)); + expect(_getLabelPadding(tester, 'Settings'), const EdgeInsets.only(top: 4)); + + await tester.pumpWidget(buildNavigationBar(labelPadding: labelPadding)); + expect(_getLabelPadding(tester, 'Home'), labelPadding); + expect(_getLabelPadding(tester, 'Settings'), labelPadding); + }); } Widget _buildWidget(Widget child, { bool? useMaterial3 }) { @@ -1577,3 +1642,12 @@ class IconWithRandomColor extends StatelessWidget { bool _sizeAlmostEqual(Size a, Size b, {double maxDiff=0.05}) { return (a.width - b.width).abs() <= maxDiff && (a.height - b.height).abs() <= maxDiff; } + +EdgeInsetsGeometry _getLabelPadding(WidgetTester tester, String text) { + return tester.widget( + find.ancestor( + of: find.text(text), + matching: find.byType(Padding), + ).first, + ).padding; +} diff --git a/packages/flutter/test/material/navigation_bar_theme_test.dart b/packages/flutter/test/material/navigation_bar_theme_test.dart index c04583f64edbc..5208a312955b7 100644 --- a/packages/flutter/test/material/navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/navigation_bar_theme_test.dart @@ -38,18 +38,21 @@ void main() { expect(description, []); }); - testWidgets('Custom debugFillProperties', (WidgetTester tester) async { + testWidgets('NavigationBarThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const NavigationBarThemeData( height: 200.0, backgroundColor: Color(0x00000099), elevation: 20.0, - indicatorColor: Color(0x00000098), + shadowColor: Color(0x00000098), + surfaceTintColor: Color(0x00000097), + indicatorColor: Color(0x00000096), indicatorShape: CircleBorder(), labelTextStyle: MaterialStatePropertyAll(TextStyle(fontSize: 7.0)), iconTheme: MaterialStatePropertyAll(IconThemeData(color: Color(0x00000097))), labelBehavior: NavigationDestinationLabelBehavior.alwaysHide, - overlayColor: MaterialStatePropertyAll(Color(0x00000096)), + overlayColor: MaterialStatePropertyAll(Color(0x00000095)), + labelPadding: EdgeInsets.all(8), ).debugFillProperties(builder); final List description = builder.properties @@ -57,17 +60,20 @@ void main() { .map((DiagnosticsNode node) => node.toString()) .toList(); - expect(description[0], 'height: 200.0'); - expect(description[1], 'backgroundColor: ${const Color(0x00000099)}'); - expect(description[2], 'elevation: 20.0'); - expect(description[3], 'indicatorColor: ${const Color(0x00000098)}'); - expect(description[4], 'indicatorShape: CircleBorder(BorderSide(width: 0.0, style: none))'); - expect(description[5], 'labelTextStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 7.0))'); - // Ignore instance address for IconThemeData. - expect(description[6].contains('iconTheme: WidgetStatePropertyAll(IconThemeData'), isTrue); - expect(description[6].contains('(color: ${const Color(0x00000097)})'), isTrue); - expect(description[7], 'labelBehavior: NavigationDestinationLabelBehavior.alwaysHide'); - expect(description[8], 'overlayColor: WidgetStatePropertyAll(${const Color(0x00000096)})'); + expect(description, equalsIgnoringHashCodes([ + 'height: 200.0', + 'backgroundColor: Color(alpha: 0.0000, red: 0.0000, green: 0.0000, blue: 0.6000, colorSpace: ColorSpace.sRGB)', + 'elevation: 20.0', + 'shadowColor: Color(alpha: 0.0000, red: 0.0000, green: 0.0000, blue: 0.5961, colorSpace: ColorSpace.sRGB)', + 'surfaceTintColor: Color(alpha: 0.0000, red: 0.0000, green: 0.0000, blue: 0.5922, colorSpace: ColorSpace.sRGB)', + 'indicatorColor: Color(alpha: 0.0000, red: 0.0000, green: 0.0000, blue: 0.5882, colorSpace: ColorSpace.sRGB)', + 'indicatorShape: CircleBorder(BorderSide(width: 0.0, style: none))', + 'labelTextStyle: WidgetStatePropertyAll(TextStyle(inherit: true, size: 7.0))', + 'iconTheme: WidgetStatePropertyAll(IconThemeData#fd5c3(color: Color(alpha: 0.0000, red: 0.0000, green: 0.0000, blue: 0.5922, colorSpace: ColorSpace.sRGB)))', + 'labelBehavior: NavigationDestinationLabelBehavior.alwaysHide', + 'overlayColor: WidgetStatePropertyAll(Color(alpha: 0.0000, red: 0.0000, green: 0.0000, blue: 0.5843, colorSpace: ColorSpace.sRGB))', + 'labelPadding: EdgeInsets.all(8.0)' + ])); }); testWidgets('NavigationBarThemeData values are used when no NavigationBar properties are specified', (WidgetTester tester) async { @@ -85,6 +91,7 @@ void main() { const double selectedLabelFontSize = 13.0; const double unselectedLabelFontSize = 11.0; const NavigationDestinationLabelBehavior labelBehavior = NavigationDestinationLabelBehavior.alwaysShow; + const EdgeInsetsGeometry labelPadding = EdgeInsets.all(8); await tester.pumpWidget( MaterialApp( @@ -117,6 +124,7 @@ void main() { return const TextStyle(fontSize: unselectedLabelFontSize); }), labelBehavior: labelBehavior, + labelPadding: labelPadding, ), child: NavigationBar( destinations: _destinations(), @@ -140,6 +148,8 @@ void main() { expect(_selectedLabelStyle(tester).fontSize, selectedLabelFontSize); expect(_unselectedLabelStyle(tester).fontSize, unselectedLabelFontSize); expect(_labelBehavior(tester), labelBehavior); + expect(_getLabelPadding(tester, 'Abc'), labelPadding); + expect(_getLabelPadding(tester, 'Def'),labelPadding); }); testWidgets('NavigationBar values take priority over NavigationBarThemeData values when both properties are specified', (WidgetTester tester) async { @@ -147,6 +157,7 @@ void main() { const Color backgroundColor = Color(0x00000001); const double elevation = 42.0; const NavigationDestinationLabelBehavior labelBehavior = NavigationDestinationLabelBehavior.alwaysShow; + const EdgeInsetsGeometry labelPadding = EdgeInsets.symmetric(horizontal: 16.0); await tester.pumpWidget( MaterialApp( @@ -157,12 +168,14 @@ void main() { elevation: 18.0, backgroundColor: Color(0x00000099), labelBehavior: NavigationDestinationLabelBehavior.alwaysHide, + labelPadding: EdgeInsets.all(8), ), child: NavigationBar( height: height, elevation: elevation, backgroundColor: backgroundColor, labelBehavior: labelBehavior, + labelPadding: labelPadding, destinations: _destinations(), ), ), @@ -174,6 +187,8 @@ void main() { expect(_barMaterial(tester).color, backgroundColor); expect(_barMaterial(tester).elevation, elevation); expect(_labelBehavior(tester), labelBehavior); + expect(_getLabelPadding(tester, 'Abc'), labelPadding); + expect(_getLabelPadding(tester, 'Def'), labelPadding); }); testWidgets('Custom label style renders ink ripple properly', (WidgetTester tester) async { @@ -400,3 +415,12 @@ double _labelOpacity(WidgetTester tester, String text) { ); return opacityWidget.opacity; } + +EdgeInsetsGeometry _getLabelPadding(WidgetTester tester, String text) { + return tester.widget( + find.ancestor( + of: find.text(text), + matching: find.byType(Padding), + ).first, + ).padding; +}