diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index cb86709e8c..c59ef61b60 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -439,39 +439,41 @@ class _NavigationRailState extends State with TickerProviderStat Expanded( child: Align( alignment: Alignment(0, groupAlignment), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - for (int i = 0; i < widget.destinations.length; i += 1) - _RailDestination( - minWidth: minWidth, - minExtendedWidth: minExtendedWidth, - extendedTransitionAnimation: _extendedAnimation, - selected: widget.selectedIndex == i, - icon: widget.selectedIndex == i ? widget.destinations[i].selectedIcon : widget.destinations[i].icon, - label: widget.destinations[i].label, - destinationAnimation: _destinationAnimations[i], - labelType: labelType, - iconTheme: widget.selectedIndex == i ? selectedIconTheme : effectiveUnselectedIconTheme, - labelTextStyle: widget.selectedIndex == i ? selectedLabelTextStyle : unselectedLabelTextStyle, - padding: widget.destinations[i].padding, - useIndicator: useIndicator, - indicatorColor: useIndicator ? indicatorColor : null, - indicatorShape: useIndicator ? indicatorShape : null, - onTap: () { - if (widget.onDestinationSelected != null) { - widget.onDestinationSelected!(i); - } - }, - indexLabel: localizations.tabLabel( - tabIndex: i + 1, - tabCount: widget.destinations.length, + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (int i = 0; i < widget.destinations.length; i += 1) + _RailDestination( + minWidth: minWidth, + minExtendedWidth: minExtendedWidth, + extendedTransitionAnimation: _extendedAnimation, + selected: widget.selectedIndex == i, + icon: widget.selectedIndex == i ? widget.destinations[i].selectedIcon : widget.destinations[i].icon, + label: widget.destinations[i].label, + destinationAnimation: _destinationAnimations[i], + labelType: labelType, + iconTheme: widget.selectedIndex == i ? selectedIconTheme : effectiveUnselectedIconTheme, + labelTextStyle: widget.selectedIndex == i ? selectedLabelTextStyle : unselectedLabelTextStyle, + padding: widget.destinations[i].padding, + useIndicator: useIndicator, + indicatorColor: useIndicator ? indicatorColor : null, + indicatorShape: useIndicator ? indicatorShape : null, + onTap: () { + if (widget.onDestinationSelected != null) { + widget.onDestinationSelected!(i); + } + }, + indexLabel: localizations.tabLabel( + tabIndex: i + 1, + tabCount: widget.destinations.length, + ), + disabled: widget.destinations[i].disabled, ), - disabled: widget.destinations[i].disabled, - ), - if (widget.trailing != null) - widget.trailing!, - ], + if (widget.trailing != null) + widget.trailing!, + ], + ), ), ), ), diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index 7085dec5de..90acfb1553 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -3605,6 +3605,62 @@ void main() { expect(inkFeatures, paints..circle(color: Colors.transparent)); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 + testWidgets('NavigationRail can scroll in low height', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/89167. + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + useMaterial3: true, + ), + home: Builder( + builder: (BuildContext context) { + return MediaQuery( + // Set Screen height with 300 + data: MediaQuery.of(context).copyWith(size: const Size(800, 300)), + child: Scaffold( + body: Row( + children: [ + // Set NavigationRail height with 100 + SizedBox( + height: 100, + child: NavigationRail( + selectedIndex: 0, + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.favorite_border), + selectedIcon: Icon(Icons.favorite), + label: Text('Abc'), + ), + NavigationRailDestination( + icon: Icon(Icons.bookmark_border), + selectedIcon: Icon(Icons.bookmark), + label: Text('Def'), + ), + NavigationRailDestination( + icon: Icon(Icons.star_border), + selectedIcon: Icon(Icons.star), + label: Text('Ghi'), + ), + ], + ), + ), + const Expanded( + child: Text('body'), + ), + ], + ), + ), + ); + }, + ), + ), + ); + + final ScrollableState scrollable = tester.state(find.byType(Scrollable)); + scrollable.position.jumpTo(500.0); + expect(scrollable.position.pixels, equals(500.0)); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests @@ -5433,31 +5489,34 @@ TestSemantics _expectedSemantics() { flags: [SemanticsFlag.scopesRoute], children: [ TestSemantics( - flags: [ - SemanticsFlag.isSelected, - SemanticsFlag.isFocusable, + flags: [SemanticsFlag.hasImplicitScrolling], + children: [ + TestSemantics( + flags: [SemanticsFlag.isSelected, + SemanticsFlag.isFocusable], + actions: [SemanticsAction.tap], + label: 'Abc\nTab 1 of 4', + textDirection: TextDirection.ltr, + ), + TestSemantics( + flags: [SemanticsFlag.isFocusable], + actions: [SemanticsAction.tap], + label: 'Def\nTab 2 of 4', + textDirection: TextDirection.ltr, + ), + TestSemantics( + flags: [SemanticsFlag.isFocusable], + actions: [SemanticsAction.tap], + label: 'Ghi\nTab 3 of 4', + textDirection: TextDirection.ltr, + ), + TestSemantics( + flags: [SemanticsFlag.isFocusable], + actions: [SemanticsAction.tap], + label: 'Jkl\nTab 4 of 4', + textDirection: TextDirection.ltr, + ), ], - actions: [SemanticsAction.tap], - label: 'Abc\nTab 1 of 4', - textDirection: TextDirection.ltr, - ), - TestSemantics( - flags: [SemanticsFlag.isFocusable], - actions: [SemanticsAction.tap], - label: 'Def\nTab 2 of 4', - textDirection: TextDirection.ltr, - ), - TestSemantics( - flags: [SemanticsFlag.isFocusable], - actions: [SemanticsAction.tap], - label: 'Ghi\nTab 3 of 4', - textDirection: TextDirection.ltr, - ), - TestSemantics( - flags: [SemanticsFlag.isFocusable], - actions: [SemanticsAction.tap], - label: 'Jkl\nTab 4 of 4', - textDirection: TextDirection.ltr, ), TestSemantics( label: 'body',