From f4cb3d215d95886994178f401ba353e64a5dfded Mon Sep 17 00:00:00 2001 From: Jack Gibbons Date: Thu, 4 Jan 2024 04:58:21 +1300 Subject: [PATCH] Add key to BottomNavigationBarItem (#139617) Pass key into _BottomNavigationTile Adding a optional key parameter to BottomNavigationBarItem to be passed through to _BottomNavigationTile. This will allow easier testing in some scenarios, and fix the splash appearing on the wrong tile. https://github.com/flutter/flutter/issues/139615 https://github.com/flutter/flutter/issues/34833 --- .../src/material/bottom_navigation_bar.dart | 2 ++ .../widgets/bottom_navigation_bar_item.dart | 9 ++++++ .../material/bottom_navigation_bar_test.dart | 28 +++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar.dart b/packages/flutter/lib/src/material/bottom_navigation_bar.dart index 3e57788995c..8df5612eb3c 100644 --- a/packages/flutter/lib/src/material/bottom_navigation_bar.dart +++ b/packages/flutter/lib/src/material/bottom_navigation_bar.dart @@ -449,6 +449,7 @@ class _BottomNavigationTile extends StatelessWidget { this.item, this.animation, this.iconSize, { + super.key, this.onTap, this.labelColorTween, this.iconColorTween, @@ -1101,6 +1102,7 @@ class _BottomNavigationBarState extends State with TickerPr widget.items[i], _animations[i], widget.iconSize, + key: widget.items[i].key, selectedIconTheme: widget.useLegacyColorScheme ? widget.selectedIconTheme ?? bottomTheme.selectedIconTheme : effectiveSelectedIconTheme, unselectedIconTheme: widget.useLegacyColorScheme ? widget.unselectedIconTheme ?? bottomTheme.unselectedIconTheme : effectiveUnselectedIconTheme, selectedLabelStyle: effectiveSelectedLabelStyle, diff --git a/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart b/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart index 6b41b5ca6b2..30bb768cf4b 100644 --- a/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart +++ b/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart @@ -23,6 +23,7 @@ class BottomNavigationBarItem { /// /// The argument [icon] should not be null and the argument [label] should not be null when used in a Material Design's [BottomNavigationBar]. const BottomNavigationBarItem({ + this.key, required this.icon, this.label, Widget? activeIcon, @@ -30,6 +31,14 @@ class BottomNavigationBarItem { this.tooltip, }) : activeIcon = activeIcon ?? icon; + /// A key to be passed through to the resultant widget. + /// + /// This allows the identification of different [BottomNavigationBarItem]s through their keys. + /// + /// When changing the number of bar items in response to a bar item being tapped, giving + /// each item a key will allow the inkwell / splash animation to be correctly positioned. + final Key? key; + /// The icon of the item. /// /// Typically the icon is an [Icon] or an [ImageIcon] widget. If another type diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index 9ae041321c6..a80164ac423 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -3174,6 +3174,34 @@ void main() { addTearDown(tester.view.resetPhysicalSize); }); + + testWidgets('BottomNavigationBar keys passed through', (WidgetTester tester) async { + const Key key1 = Key('key1'); + const Key key2 = Key('key2'); + + await tester.pumpWidget( + boilerplate( + textDirection: TextDirection.ltr, + bottomNavigationBar: BottomNavigationBar( + items: const [ + BottomNavigationBarItem( + key: key1, + icon: Icon(Icons.favorite_border), + label: 'Favorite', + ), + BottomNavigationBarItem( + key: key2, + icon: Icon(Icons.access_alarm), + label: 'Alarm', + ), + ], + ), + ), + ); + + expect(find.byKey(key1), findsOneWidget); + expect(find.byKey(key2), findsOneWidget); + }); } Widget boilerplate({ Widget? bottomNavigationBar, required TextDirection textDirection, bool? useMaterial3 }) {