Unverified Commit 2b621e1a authored by Qun Cheng's avatar Qun Cheng Committed by GitHub

Add SafeArea for NavigationRail (#107605)

* Added SafeArea for NavigationRail
Co-authored-by: 's avatarQun Cheng <quncheng@google.com>
parent 7976287e
...@@ -402,6 +402,8 @@ class _NavigationRailState extends State<NavigationRail> with TickerProviderStat ...@@ -402,6 +402,8 @@ class _NavigationRailState extends State<NavigationRail> with TickerProviderStat
? unselectedIconTheme ? unselectedIconTheme
: unselectedIconTheme.copyWith(opacity: unselectedIconTheme.opacity ?? defaults.unselectedIconTheme!.opacity); : unselectedIconTheme.copyWith(opacity: unselectedIconTheme.opacity ?? defaults.unselectedIconTheme!.opacity);
final bool isRTLDirection = Directionality.of(context) == TextDirection.rtl;
return _ExtendedNavigationRailAnimation( return _ExtendedNavigationRailAnimation(
animation: _extendedAnimation, animation: _extendedAnimation,
child: Semantics( child: Semantics(
...@@ -409,52 +411,56 @@ class _NavigationRailState extends State<NavigationRail> with TickerProviderStat ...@@ -409,52 +411,56 @@ class _NavigationRailState extends State<NavigationRail> with TickerProviderStat
child: Material( child: Material(
elevation: elevation, elevation: elevation,
color: backgroundColor, color: backgroundColor,
child: Column( child: SafeArea(
children: <Widget>[ right: isRTLDirection,
_verticalSpacer, left: !isRTLDirection,
if (widget.leading != null) child: Column(
...<Widget>[ children: <Widget>[
widget.leading!, _verticalSpacer,
_verticalSpacer, if (widget.leading != null)
], ...<Widget>[
Expanded( widget.leading!,
child: Align( _verticalSpacer,
alignment: Alignment(0, groupAlignment), ],
child: Column( Expanded(
mainAxisSize: MainAxisSize.min, child: Align(
children: <Widget>[ alignment: Alignment(0, groupAlignment),
for (int i = 0; i < widget.destinations.length; i += 1) child: Column(
_RailDestination( mainAxisSize: MainAxisSize.min,
minWidth: minWidth, children: <Widget>[
minExtendedWidth: minExtendedWidth, for (int i = 0; i < widget.destinations.length; i += 1)
extendedTransitionAnimation: _extendedAnimation, _RailDestination(
selected: widget.selectedIndex == i, minWidth: minWidth,
icon: widget.selectedIndex == i ? widget.destinations[i].selectedIcon : widget.destinations[i].icon, minExtendedWidth: minExtendedWidth,
label: widget.destinations[i].label, extendedTransitionAnimation: _extendedAnimation,
destinationAnimation: _destinationAnimations[i], selected: widget.selectedIndex == i,
labelType: labelType, icon: widget.selectedIndex == i ? widget.destinations[i].selectedIcon : widget.destinations[i].icon,
iconTheme: widget.selectedIndex == i ? selectedIconTheme : effectiveUnselectedIconTheme, label: widget.destinations[i].label,
labelTextStyle: widget.selectedIndex == i ? selectedLabelTextStyle : unselectedLabelTextStyle, destinationAnimation: _destinationAnimations[i],
padding: widget.destinations[i].padding, labelType: labelType,
useIndicator: useIndicator, iconTheme: widget.selectedIndex == i ? selectedIconTheme : effectiveUnselectedIconTheme,
indicatorColor: useIndicator ? indicatorColor : null, labelTextStyle: widget.selectedIndex == i ? selectedLabelTextStyle : unselectedLabelTextStyle,
onTap: () { padding: widget.destinations[i].padding,
if (widget.onDestinationSelected != null) { useIndicator: useIndicator,
widget.onDestinationSelected!(i); indicatorColor: useIndicator ? indicatorColor : null,
} onTap: () {
}, if (widget.onDestinationSelected != null) {
indexLabel: localizations.tabLabel( widget.onDestinationSelected!(i);
tabIndex: i + 1, }
tabCount: widget.destinations.length, },
indexLabel: localizations.tabLabel(
tabIndex: i + 1,
tabCount: widget.destinations.length,
),
), ),
), if (widget.trailing != null)
if (widget.trailing != null) widget.trailing!,
widget.trailing!, ],
], ),
), ),
), ),
), ],
], ),
), ),
), ),
), ),
......
...@@ -2314,9 +2314,15 @@ void main() { ...@@ -2314,9 +2314,15 @@ void main() {
), ),
); );
final Padding firstItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Abc')); final Padding firstItem = tester.widget<Padding>(
final Padding secondItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Def')); find.descendant(of: find.widgetWithText(InkResponse, 'Abc'), matching: find.widgetWithText(Padding, 'Abc'))
final Padding thirdItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Ghi')); );
final Padding secondItem = tester.widget<Padding>(
find.descendant(of: find.widgetWithText(InkResponse, 'Def'), matching: find.widgetWithText(Padding, 'Def'))
);
final Padding thirdItem = tester.widget<Padding>(
find.descendant(of: find.widgetWithText(InkResponse, 'Ghi'), matching: find.widgetWithText(Padding, 'Ghi'))
);
expect(firstItem.padding, defaultPadding); expect(firstItem.padding, defaultPadding);
expect(secondItem.padding, secondItemPadding); expect(secondItem.padding, secondItemPadding);
...@@ -2355,9 +2361,15 @@ void main() { ...@@ -2355,9 +2361,15 @@ void main() {
), ),
); );
final Padding firstItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Abc')); final Padding firstItem = tester.widget<Padding>(
final Padding secondItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Def')); find.descendant(of: find.widgetWithText(InkResponse, 'Abc'), matching: find.widgetWithText(Padding, 'Abc'))
final Padding thirdItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Ghi')); );
final Padding secondItem = tester.widget<Padding>(
find.descendant(of: find.widgetWithText(InkResponse, 'Def'), matching: find.widgetWithText(Padding, 'Def'))
);
final Padding thirdItem = tester.widget<Padding>(
find.descendant(of: find.widgetWithText(InkResponse, 'Ghi'), matching: find.widgetWithText(Padding, 'Ghi'))
);
expect(firstItem.padding, defaultPadding); expect(firstItem.padding, defaultPadding);
expect(secondItem.padding, secondItemPadding); expect(secondItem.padding, secondItemPadding);
...@@ -2396,9 +2408,15 @@ void main() { ...@@ -2396,9 +2408,15 @@ void main() {
), ),
); );
final Padding firstItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Abc')); final Padding firstItem = tester.widget<Padding>(
final Padding secondItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Def')); find.descendant(of: find.widgetWithText(InkResponse, 'Abc'), matching: find.widgetWithText(Padding, 'Abc'))
final Padding thirdItem = tester.widget<Padding>(find.widgetWithText(Padding, 'Ghi')); );
final Padding secondItem = tester.widget<Padding>(
find.descendant(of: find.widgetWithText(InkResponse, 'Def'), matching: find.widgetWithText(Padding, 'Def'))
);
final Padding thirdItem = tester.widget<Padding>(
find.descendant(of: find.widgetWithText(InkResponse, 'Ghi'), matching: find.widgetWithText(Padding, 'Ghi'))
);
expect(firstItem.padding, defaultPadding); expect(firstItem.padding, defaultPadding);
expect(secondItem.padding, secondItemPadding); expect(secondItem.padding, secondItemPadding);
...@@ -2637,6 +2655,59 @@ void main() { ...@@ -2637,6 +2655,59 @@ void main() {
expect(lastIndicator.localToGlobal(Offset.zero).dx, 28.0); expect(lastIndicator.localToGlobal(Offset.zero).dx, 28.0);
}); });
testWidgets('NavigationRail respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async {
const double safeAreaPadding = 40.0;
NavigationRail navigationRail() {
return NavigationRail(
selectedIndex: 0,
destinations: const <NavigationRailDestination>[
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'),
),
],
);
}
await tester.pumpWidget(_buildWidget(navigationRail()));
final double defaultWidth = tester.getSize(find.byType(NavigationRail)).width;
expect(defaultWidth, 80);
await tester.pumpWidget(
_buildWidget(
MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.only(left: safeAreaPadding),
),
child: navigationRail(),
),
),
);
final double updatedWidth = tester.getSize(find.byType(NavigationRail)).width;
expect(updatedWidth, defaultWidth + safeAreaPadding);
// test width when text direction is RTL.
await tester.pumpWidget(
_buildWidget(
MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.only(right: safeAreaPadding),
),
child: navigationRail(),
),
isRTL: true,
),
);
final double updatedWidthRTL = tester.getSize(find.byType(NavigationRail)).width;
expect(updatedWidthRTL, defaultWidth + safeAreaPadding);
});
group('Material 2', () { group('Material 2', () {
// Original Material 2 tests. Remove this group after `useMaterial3` has been deprecated. // Original Material 2 tests. Remove this group after `useMaterial3` has been deprecated.
testWidgets('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async { testWidgets('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async {
...@@ -4392,6 +4463,61 @@ void main() { ...@@ -4392,6 +4463,61 @@ void main() {
expect(lastIndicator.localToGlobal(Offset.zero).dx, 24.0); expect(lastIndicator.localToGlobal(Offset.zero).dx, 24.0);
}); });
testWidgets('NavigationRail respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async {
const double safeAreaPadding = 40.0;
NavigationRail navigationRail() {
return NavigationRail(
selectedIndex: 0,
destinations: const <NavigationRailDestination>[
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'),
),
],
);
}
await tester.pumpWidget(_buildWidget(navigationRail(), useMaterial3: false));
final double defaultWidth = tester.getSize(find.byType(NavigationRail)).width;
expect(defaultWidth, 72);
await tester.pumpWidget(
_buildWidget(
MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.only(left: safeAreaPadding),
),
child: navigationRail(),
),
useMaterial3: false
),
);
final double updatedWidth = tester.getSize(find.byType(NavigationRail)).width;
expect(updatedWidth, defaultWidth + safeAreaPadding);
// test width when text direction is RTL.
await tester.pumpWidget(
_buildWidget(
MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.only(right: safeAreaPadding),
),
child: navigationRail(),
),
useMaterial3: false,
isRTL: true,
),
);
final double updatedWidthRTL = tester.getSize(find.byType(NavigationRail)).width;
expect(updatedWidthRTL, defaultWidth + safeAreaPadding);
});
}); // End Material 2 group }); // End Material 2 group
} }
...@@ -4595,3 +4721,22 @@ Material _railMaterial(WidgetTester tester) { ...@@ -4595,3 +4721,22 @@ Material _railMaterial(WidgetTester tester) {
), ),
); );
} }
Widget _buildWidget(Widget child, {bool useMaterial3 = true, bool isRTL = false}) {
return MaterialApp(
theme: ThemeData(useMaterial3: useMaterial3),
home: Directionality(
textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
child: Scaffold(
body: Row(
children: <Widget>[
child,
const Expanded(
child: Text('body'),
),
],
),
),
),
);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment