Add indicatorColor
& indicatorShape
to NavigationRail
, NavigationDrawer
and move these properties from destination to NavigationBar
(#117049)
This commit is contained in:
parent
32da25053d
commit
cb988c7b6e
@ -93,6 +93,8 @@ class NavigationBar extends StatelessWidget {
|
|||||||
this.elevation,
|
this.elevation,
|
||||||
this.shadowColor,
|
this.shadowColor,
|
||||||
this.surfaceTintColor,
|
this.surfaceTintColor,
|
||||||
|
this.indicatorColor,
|
||||||
|
this.indicatorShape,
|
||||||
this.height,
|
this.height,
|
||||||
this.labelBehavior,
|
this.labelBehavior,
|
||||||
}) : assert(destinations != null && destinations.length >= 2),
|
}) : assert(destinations != null && destinations.length >= 2),
|
||||||
@ -158,6 +160,20 @@ class NavigationBar extends StatelessWidget {
|
|||||||
/// overlay is applied.
|
/// overlay is applied.
|
||||||
final Color? surfaceTintColor;
|
final Color? surfaceTintColor;
|
||||||
|
|
||||||
|
/// The color of the [indicatorShape] when this destination is selected.
|
||||||
|
///
|
||||||
|
/// If null, [NavigationBarThemeData.indicatorColor] is used. If that
|
||||||
|
/// is also null and [ThemeData.useMaterial3] is true, [ColorScheme.secondaryContainer]
|
||||||
|
/// is used. Otherwise, [ColorScheme.secondary] with an opacity of 0.24 is used.
|
||||||
|
final Color? indicatorColor;
|
||||||
|
|
||||||
|
/// The shape of the selected inidicator.
|
||||||
|
///
|
||||||
|
/// If null, [NavigationBarThemeData.indicatorShape] is used. If that
|
||||||
|
/// is also null and [ThemeData.useMaterial3] is true, [StadiumBorder] is used.
|
||||||
|
/// Otherwise, [RoundedRectangleBorder] with a circular border radius of 16 is used.
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
|
||||||
/// The height of the [NavigationBar] itself.
|
/// The height of the [NavigationBar] itself.
|
||||||
///
|
///
|
||||||
/// If this is used in [Scaffold.bottomNavigationBar] and the scaffold is
|
/// If this is used in [Scaffold.bottomNavigationBar] and the scaffold is
|
||||||
@ -224,6 +240,8 @@ class NavigationBar extends StatelessWidget {
|
|||||||
totalNumberOfDestinations: destinations.length,
|
totalNumberOfDestinations: destinations.length,
|
||||||
selectedAnimation: animation,
|
selectedAnimation: animation,
|
||||||
labelBehavior: effectiveLabelBehavior,
|
labelBehavior: effectiveLabelBehavior,
|
||||||
|
indicatorColor: indicatorColor,
|
||||||
|
indicatorShape: indicatorShape,
|
||||||
onTap: _handleTap(i),
|
onTap: _handleTap(i),
|
||||||
child: destinations[i],
|
child: destinations[i],
|
||||||
);
|
);
|
||||||
@ -274,8 +292,6 @@ class NavigationDestination extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
this.selectedIcon,
|
this.selectedIcon,
|
||||||
this.indicatorColor,
|
|
||||||
this.indicatorShape,
|
|
||||||
required this.label,
|
required this.label,
|
||||||
this.tooltip,
|
this.tooltip,
|
||||||
});
|
});
|
||||||
@ -300,12 +316,6 @@ class NavigationDestination extends StatelessWidget {
|
|||||||
/// would use a size of 24.0 and [ColorScheme.onSurface].
|
/// would use a size of 24.0 and [ColorScheme.onSurface].
|
||||||
final Widget? selectedIcon;
|
final Widget? selectedIcon;
|
||||||
|
|
||||||
/// The color of the [indicatorShape] when this destination is selected.
|
|
||||||
final Color? indicatorColor;
|
|
||||||
|
|
||||||
/// The shape of the selected inidicator.
|
|
||||||
final ShapeBorder? indicatorShape;
|
|
||||||
|
|
||||||
/// The text label that appears below the icon of this
|
/// The text label that appears below the icon of this
|
||||||
/// [NavigationDestination].
|
/// [NavigationDestination].
|
||||||
///
|
///
|
||||||
@ -324,12 +334,13 @@ class NavigationDestination extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _NavigationDestinationInfo info = _NavigationDestinationInfo.of(context);
|
||||||
const Set<MaterialState> selectedState = <MaterialState>{MaterialState.selected};
|
const Set<MaterialState> selectedState = <MaterialState>{MaterialState.selected};
|
||||||
const Set<MaterialState> unselectedState = <MaterialState>{};
|
const Set<MaterialState> unselectedState = <MaterialState>{};
|
||||||
|
|
||||||
final NavigationBarThemeData navigationBarTheme = NavigationBarTheme.of(context);
|
final NavigationBarThemeData navigationBarTheme = NavigationBarTheme.of(context);
|
||||||
final NavigationBarThemeData defaults = _defaultsFor(context);
|
final NavigationBarThemeData defaults = _defaultsFor(context);
|
||||||
final Animation<double> animation = _NavigationDestinationInfo.of(context).selectedAnimation;
|
final Animation<double> animation = info.selectedAnimation;
|
||||||
|
|
||||||
return _NavigationDestinationBuilder(
|
return _NavigationDestinationBuilder(
|
||||||
label: label,
|
label: label,
|
||||||
@ -351,8 +362,8 @@ class NavigationDestination extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
NavigationIndicator(
|
NavigationIndicator(
|
||||||
animation: animation,
|
animation: animation,
|
||||||
color: indicatorColor ?? navigationBarTheme.indicatorColor ?? defaults.indicatorColor!,
|
color: info.indicatorColor ?? navigationBarTheme.indicatorColor ?? defaults.indicatorColor!,
|
||||||
shape: indicatorShape ?? navigationBarTheme.indicatorShape ?? defaults.indicatorShape!
|
shape: info.indicatorShape ?? navigationBarTheme.indicatorShape ?? defaults.indicatorShape!
|
||||||
),
|
),
|
||||||
_StatusTransitionWidgetBuilder(
|
_StatusTransitionWidgetBuilder(
|
||||||
animation: animation,
|
animation: animation,
|
||||||
@ -532,6 +543,8 @@ class _NavigationDestinationInfo extends InheritedWidget {
|
|||||||
required this.totalNumberOfDestinations,
|
required this.totalNumberOfDestinations,
|
||||||
required this.selectedAnimation,
|
required this.selectedAnimation,
|
||||||
required this.labelBehavior,
|
required this.labelBehavior,
|
||||||
|
required this.indicatorColor,
|
||||||
|
required this.indicatorShape,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
required super.child,
|
required super.child,
|
||||||
});
|
});
|
||||||
@ -588,6 +601,16 @@ class _NavigationDestinationInfo extends InheritedWidget {
|
|||||||
/// label, or hide all labels.
|
/// label, or hide all labels.
|
||||||
final NavigationDestinationLabelBehavior labelBehavior;
|
final NavigationDestinationLabelBehavior labelBehavior;
|
||||||
|
|
||||||
|
/// The color of the selection indicator.
|
||||||
|
///
|
||||||
|
/// This is used by destinations to override the indicator color.
|
||||||
|
final Color? indicatorColor;
|
||||||
|
|
||||||
|
/// The shape of the selection indicator.
|
||||||
|
///
|
||||||
|
/// This is used by destinations to override the indicator shape.
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
|
||||||
/// The callback that should be called when this destination is tapped.
|
/// The callback that should be called when this destination is tapped.
|
||||||
///
|
///
|
||||||
/// This is computed by calling [NavigationBar.onDestinationSelected]
|
/// This is computed by calling [NavigationBar.onDestinationSelected]
|
||||||
|
@ -57,6 +57,8 @@ class NavigationDrawer extends StatelessWidget {
|
|||||||
this.shadowColor,
|
this.shadowColor,
|
||||||
this.surfaceTintColor,
|
this.surfaceTintColor,
|
||||||
this.elevation,
|
this.elevation,
|
||||||
|
this.indicatorColor,
|
||||||
|
this.indicatorShape,
|
||||||
this.onDestinationSelected,
|
this.onDestinationSelected,
|
||||||
this.selectedIndex = 0,
|
this.selectedIndex = 0,
|
||||||
});
|
});
|
||||||
@ -90,6 +92,18 @@ class NavigationDrawer extends StatelessWidget {
|
|||||||
/// is also null, it will be 1.0.
|
/// is also null, it will be 1.0.
|
||||||
final double? elevation;
|
final double? elevation;
|
||||||
|
|
||||||
|
/// The color of the [indicatorShape] when this destination is selected.
|
||||||
|
///
|
||||||
|
/// If this is null, [NavigationDrawerThemeData.indicatorColor] is used.
|
||||||
|
/// If that is also null, defaults to [ColorScheme.secondaryContainer].
|
||||||
|
final Color? indicatorColor;
|
||||||
|
|
||||||
|
/// The shape of the selected inidicator.
|
||||||
|
///
|
||||||
|
/// If this is null, [NavigationDrawerThemeData.indicatorShape] is used.
|
||||||
|
/// If that is also null, defaults to [StadiumBorder].
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
|
||||||
/// Defines the appearance of the items within the navigation drawer.
|
/// Defines the appearance of the items within the navigation drawer.
|
||||||
///
|
///
|
||||||
/// The list contains [NavigationDrawerDestination] widgets and/or customized
|
/// The list contains [NavigationDrawerDestination] widgets and/or customized
|
||||||
@ -125,6 +139,8 @@ class NavigationDrawer extends StatelessWidget {
|
|||||||
index: index,
|
index: index,
|
||||||
totalNumberOfDestinations: totalNumberOfDestinations,
|
totalNumberOfDestinations: totalNumberOfDestinations,
|
||||||
selectedAnimation: animation,
|
selectedAnimation: animation,
|
||||||
|
indicatorColor: indicatorColor,
|
||||||
|
indicatorShape: indicatorShape,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (onDestinationSelected != null) {
|
if (onDestinationSelected != null) {
|
||||||
onDestinationSelected!(index);
|
onDestinationSelected!(index);
|
||||||
@ -315,9 +331,9 @@ class _NavigationDestinationBuilder extends StatelessWidget {
|
|||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
NavigationIndicator(
|
NavigationIndicator(
|
||||||
animation: _NavigationDrawerDestinationInfo.of(context).selectedAnimation,
|
animation: info.selectedAnimation,
|
||||||
color: navigationDrawerTheme.indicatorColor ?? defaults.indicatorColor!,
|
color: info.indicatorColor ?? navigationDrawerTheme.indicatorColor ?? defaults.indicatorColor!,
|
||||||
shape: navigationDrawerTheme.indicatorShape ?? defaults.indicatorShape!,
|
shape: info.indicatorShape ?? navigationDrawerTheme.indicatorShape ?? defaults.indicatorShape!,
|
||||||
width: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).width,
|
width: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).width,
|
||||||
height: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).height,
|
height: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).height,
|
||||||
),
|
),
|
||||||
@ -433,6 +449,8 @@ class _NavigationDrawerDestinationInfo extends InheritedWidget {
|
|||||||
required this.index,
|
required this.index,
|
||||||
required this.totalNumberOfDestinations,
|
required this.totalNumberOfDestinations,
|
||||||
required this.selectedAnimation,
|
required this.selectedAnimation,
|
||||||
|
required this.indicatorColor,
|
||||||
|
required this.indicatorShape,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
required super.child,
|
required super.child,
|
||||||
});
|
});
|
||||||
@ -478,6 +496,16 @@ class _NavigationDrawerDestinationInfo extends InheritedWidget {
|
|||||||
/// to 1 (selected).
|
/// to 1 (selected).
|
||||||
final Animation<double> selectedAnimation;
|
final Animation<double> selectedAnimation;
|
||||||
|
|
||||||
|
/// The color of the indicator.
|
||||||
|
///
|
||||||
|
/// This is used by destinations to override the indicator color.
|
||||||
|
final Color? indicatorColor;
|
||||||
|
|
||||||
|
/// The shape of the indicator.
|
||||||
|
///
|
||||||
|
/// This is used by destinations to override the indicator shape.
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
|
||||||
/// The callback that should be called when this destination is tapped.
|
/// The callback that should be called when this destination is tapped.
|
||||||
///
|
///
|
||||||
/// This is computed by calling [NavigationDrawer.onDestinationSelected]
|
/// This is computed by calling [NavigationDrawer.onDestinationSelected]
|
||||||
|
@ -110,6 +110,7 @@ class NavigationRail extends StatefulWidget {
|
|||||||
this.minExtendedWidth,
|
this.minExtendedWidth,
|
||||||
this.useIndicator,
|
this.useIndicator,
|
||||||
this.indicatorColor,
|
this.indicatorColor,
|
||||||
|
this.indicatorShape,
|
||||||
}) : assert(destinations != null && destinations.length >= 2),
|
}) : assert(destinations != null && destinations.length >= 2),
|
||||||
assert(selectedIndex == null || (0 <= selectedIndex && selectedIndex < destinations.length)),
|
assert(selectedIndex == null || (0 <= selectedIndex && selectedIndex < destinations.length)),
|
||||||
assert(elevation == null || elevation > 0),
|
assert(elevation == null || elevation > 0),
|
||||||
@ -306,8 +307,18 @@ class NavigationRail extends StatefulWidget {
|
|||||||
|
|
||||||
/// Overrides the default value of [NavigationRail]'s selection indicator color,
|
/// Overrides the default value of [NavigationRail]'s selection indicator color,
|
||||||
/// when [useIndicator] is true.
|
/// when [useIndicator] is true.
|
||||||
|
///
|
||||||
|
/// If this is null, [NavigationRailThemeData.indicatorColor] is used. If
|
||||||
|
/// that is null, defaults to [ColorScheme.secondaryContainer].
|
||||||
final Color? indicatorColor;
|
final Color? indicatorColor;
|
||||||
|
|
||||||
|
/// Overrides the default value of [NavigationRail]'s selection indicator shape,
|
||||||
|
/// when [useIndicator] is true.
|
||||||
|
///
|
||||||
|
/// If this is null, [NavigationRailThemeData.indicatorShape] is used. If
|
||||||
|
/// that is null, defaults to [StadiumBorder].
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
|
||||||
/// Returns the animation that controls the [NavigationRail.extended] state.
|
/// Returns the animation that controls the [NavigationRail.extended] state.
|
||||||
///
|
///
|
||||||
/// This can be used to synchronize animations in the [leading] or [trailing]
|
/// This can be used to synchronize animations in the [leading] or [trailing]
|
||||||
@ -396,7 +407,7 @@ class _NavigationRailState extends State<NavigationRail> with TickerProviderStat
|
|||||||
final NavigationRailLabelType labelType = widget.labelType ?? navigationRailTheme.labelType ?? defaults.labelType!;
|
final NavigationRailLabelType labelType = widget.labelType ?? navigationRailTheme.labelType ?? defaults.labelType!;
|
||||||
final bool useIndicator = widget.useIndicator ?? navigationRailTheme.useIndicator ?? defaults.useIndicator!;
|
final bool useIndicator = widget.useIndicator ?? navigationRailTheme.useIndicator ?? defaults.useIndicator!;
|
||||||
final Color? indicatorColor = widget.indicatorColor ?? navigationRailTheme.indicatorColor ?? defaults.indicatorColor;
|
final Color? indicatorColor = widget.indicatorColor ?? navigationRailTheme.indicatorColor ?? defaults.indicatorColor;
|
||||||
final ShapeBorder? indicatorShape = navigationRailTheme.indicatorShape ?? defaults.indicatorShape;
|
final ShapeBorder? indicatorShape = widget.indicatorShape ?? navigationRailTheme.indicatorShape ?? defaults.indicatorShape;
|
||||||
|
|
||||||
// For backwards compatibility, in M2 the opacity of the unselected icons needs
|
// For backwards compatibility, in M2 the opacity of the unselected icons needs
|
||||||
// to be set to the default if it isn't in the given theme. This can be removed
|
// to be set to the default if it isn't in the given theme. This can be removed
|
||||||
@ -900,6 +911,8 @@ class NavigationRailDestination {
|
|||||||
const NavigationRailDestination({
|
const NavigationRailDestination({
|
||||||
required this.icon,
|
required this.icon,
|
||||||
Widget? selectedIcon,
|
Widget? selectedIcon,
|
||||||
|
this.indicatorColor,
|
||||||
|
this.indicatorShape,
|
||||||
required this.label,
|
required this.label,
|
||||||
this.padding,
|
this.padding,
|
||||||
}) : selectedIcon = selectedIcon ?? icon,
|
}) : selectedIcon = selectedIcon ?? icon,
|
||||||
@ -933,6 +946,12 @@ class NavigationRailDestination {
|
|||||||
/// icons.
|
/// icons.
|
||||||
final Widget selectedIcon;
|
final Widget selectedIcon;
|
||||||
|
|
||||||
|
/// The color of the [indicatorShape] when this destination is selected.
|
||||||
|
final Color? indicatorColor;
|
||||||
|
|
||||||
|
/// The shape of the selection inidicator.
|
||||||
|
final ShapeBorder? indicatorShape;
|
||||||
|
|
||||||
/// The label for the destination.
|
/// The label for the destination.
|
||||||
///
|
///
|
||||||
/// The label must be provided when used with the [NavigationRail]. When the
|
/// The label must be provided when used with the [NavigationRail]. When the
|
||||||
|
@ -263,8 +263,8 @@ void main() {
|
|||||||
expect(_getMaterial(tester).surfaceTintColor, null);
|
expect(_getMaterial(tester).surfaceTintColor, null);
|
||||||
expect(_getMaterial(tester).elevation, 0);
|
expect(_getMaterial(tester).elevation, 0);
|
||||||
expect(tester.getSize(find.byType(NavigationBar)).height, 80);
|
expect(tester.getSize(find.byType(NavigationBar)).height, 80);
|
||||||
expect(_indicator(tester)?.color, const Color(0x3d2196f3));
|
expect(_getIndicatorDecoration(tester)?.color, const Color(0x3d2196f3));
|
||||||
expect(_indicator(tester)?.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)));
|
expect(_getIndicatorDecoration(tester)?.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)));
|
||||||
|
|
||||||
// M3 settings from the token database.
|
// M3 settings from the token database.
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
@ -292,8 +292,8 @@ void main() {
|
|||||||
expect(_getMaterial(tester).surfaceTintColor, ThemeData().colorScheme.surfaceTint);
|
expect(_getMaterial(tester).surfaceTintColor, ThemeData().colorScheme.surfaceTint);
|
||||||
expect(_getMaterial(tester).elevation, 3);
|
expect(_getMaterial(tester).elevation, 3);
|
||||||
expect(tester.getSize(find.byType(NavigationBar)).height, 80);
|
expect(tester.getSize(find.byType(NavigationBar)).height, 80);
|
||||||
expect(_indicator(tester)?.color, const Color(0xff2196f3));
|
expect(_getIndicatorDecoration(tester)?.color, const Color(0xff2196f3));
|
||||||
expect(_indicator(tester)?.shape, const StadiumBorder());
|
expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('NavigationBar shows tooltips with text scaling ', (WidgetTester tester) async {
|
testWidgets('NavigationBar shows tooltips with text scaling ', (WidgetTester tester) async {
|
||||||
@ -807,21 +807,21 @@ void main() {
|
|||||||
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
|
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: true);
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
const Color color = Color(0xff0000ff);
|
const Color color = Color(0xff0000ff);
|
||||||
const ShapeBorder shape = CircleBorder();
|
const ShapeBorder shape = RoundedRectangleBorder();
|
||||||
|
|
||||||
Widget buildNaviagationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) {
|
Widget buildNavigationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
theme: theme,
|
theme: theme,
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: NavigationBar(
|
bottomNavigationBar: NavigationBar(
|
||||||
destinations: <Widget>[
|
|
||||||
NavigationDestination(
|
|
||||||
icon: const Icon(Icons.ac_unit),
|
|
||||||
label: 'AC',
|
|
||||||
indicatorColor: indicatorColor,
|
indicatorColor: indicatorColor,
|
||||||
indicatorShape: indicatorShape,
|
indicatorShape: indicatorShape,
|
||||||
|
destinations: const <Widget>[
|
||||||
|
NavigationDestination(
|
||||||
|
icon: Icon(Icons.ac_unit),
|
||||||
|
label: 'AC',
|
||||||
),
|
),
|
||||||
const NavigationDestination(
|
NavigationDestination(
|
||||||
icon: Icon(Icons.access_alarm),
|
icon: Icon(Icons.access_alarm),
|
||||||
label: 'Alarm',
|
label: 'Alarm',
|
||||||
),
|
),
|
||||||
@ -832,17 +832,17 @@ void main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await tester.pumpWidget(buildNaviagationBar());
|
await tester.pumpWidget(buildNavigationBar());
|
||||||
|
|
||||||
// Test default indicator color and shape.
|
// Test default indicator color and shape.
|
||||||
expect(_indicator(tester)?.color, theme.colorScheme.secondaryContainer);
|
expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondaryContainer);
|
||||||
expect(_indicator(tester)?.shape, const StadiumBorder());
|
expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
|
||||||
|
|
||||||
await tester.pumpWidget(buildNaviagationBar(indicatorColor: color, indicatorShape: shape));
|
await tester.pumpWidget(buildNavigationBar(indicatorColor: color, indicatorShape: shape));
|
||||||
|
|
||||||
// Test custom indicator color and shape.
|
// Test custom indicator color and shape.
|
||||||
expect(_indicator(tester)?.color, color);
|
expect(_getIndicatorDecoration(tester)?.color, color);
|
||||||
expect(_indicator(tester)?.shape, shape);
|
expect(_getIndicatorDecoration(tester)?.shape, shape);
|
||||||
});
|
});
|
||||||
|
|
||||||
group('Material 2', () {
|
group('Material 2', () {
|
||||||
@ -852,21 +852,21 @@ void main() {
|
|||||||
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
|
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
|
||||||
final ThemeData theme = ThemeData(useMaterial3: false);
|
final ThemeData theme = ThemeData(useMaterial3: false);
|
||||||
const Color color = Color(0xff0000ff);
|
const Color color = Color(0xff0000ff);
|
||||||
const ShapeBorder shape = CircleBorder();
|
const ShapeBorder shape = RoundedRectangleBorder();
|
||||||
|
|
||||||
Widget buildNaviagationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) {
|
Widget buildNavigationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
theme: theme,
|
theme: theme,
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: NavigationBar(
|
bottomNavigationBar: NavigationBar(
|
||||||
destinations: <Widget>[
|
|
||||||
NavigationDestination(
|
|
||||||
icon: const Icon(Icons.ac_unit),
|
|
||||||
label: 'AC',
|
|
||||||
indicatorColor: indicatorColor,
|
indicatorColor: indicatorColor,
|
||||||
indicatorShape: indicatorShape,
|
indicatorShape: indicatorShape,
|
||||||
|
destinations: const <Widget>[
|
||||||
|
NavigationDestination(
|
||||||
|
icon: Icon(Icons.ac_unit),
|
||||||
|
label: 'AC',
|
||||||
),
|
),
|
||||||
const NavigationDestination(
|
NavigationDestination(
|
||||||
icon: Icon(Icons.access_alarm),
|
icon: Icon(Icons.access_alarm),
|
||||||
label: 'Alarm',
|
label: 'Alarm',
|
||||||
),
|
),
|
||||||
@ -877,20 +877,20 @@ void main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await tester.pumpWidget(buildNaviagationBar());
|
await tester.pumpWidget(buildNavigationBar());
|
||||||
|
|
||||||
// Test default indicator color and shape.
|
// Test default indicator color and shape.
|
||||||
expect(_indicator(tester)?.color, theme.colorScheme.secondary.withOpacity(0.24));
|
expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondary.withOpacity(0.24));
|
||||||
expect(
|
expect(
|
||||||
_indicator(tester)?.shape,
|
_getIndicatorDecoration(tester)?.shape,
|
||||||
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||||
);
|
);
|
||||||
|
|
||||||
await tester.pumpWidget(buildNaviagationBar(indicatorColor: color, indicatorShape: shape));
|
await tester.pumpWidget(buildNavigationBar(indicatorColor: color, indicatorShape: shape));
|
||||||
|
|
||||||
// Test custom indicator color and shape.
|
// Test custom indicator color and shape.
|
||||||
expect(_indicator(tester)?.color, color);
|
expect(_getIndicatorDecoration(tester)?.color, color);
|
||||||
expect(_indicator(tester)?.shape, shape);
|
expect(_getIndicatorDecoration(tester)?.shape, shape);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -912,7 +912,7 @@ Material _getMaterial(WidgetTester tester) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeDecoration? _indicator(WidgetTester tester) {
|
ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) {
|
||||||
return tester.firstWidget<Container>(
|
return tester.firstWidget<Container>(
|
||||||
find.descendant(
|
find.descendant(
|
||||||
of: find.byType(FadeTransition),
|
of: find.byType(FadeTransition),
|
||||||
|
@ -149,8 +149,8 @@ void main() {
|
|||||||
expect(_getMaterial(tester).surfaceTintColor,
|
expect(_getMaterial(tester).surfaceTintColor,
|
||||||
ThemeData().colorScheme.surfaceTint);
|
ThemeData().colorScheme.surfaceTint);
|
||||||
expect(_getMaterial(tester).elevation, 1);
|
expect(_getMaterial(tester).elevation, 1);
|
||||||
expect(_indicator(tester)?.color, const Color(0xff2196f3));
|
expect(_getIndicatorDecoration(tester)?.color, const Color(0xff2196f3));
|
||||||
expect(_indicator(tester)?.shape, const StadiumBorder());
|
expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Navigation drawer semantics', (WidgetTester tester) async {
|
testWidgets('Navigation drawer semantics', (WidgetTester tester) async {
|
||||||
@ -222,6 +222,53 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
|
||||||
|
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
|
const Color color = Color(0xff0000ff);
|
||||||
|
const ShapeBorder shape = RoundedRectangleBorder();
|
||||||
|
|
||||||
|
Widget buildNavigationDrawer({Color? indicatorColor, ShapeBorder? indicatorShape}) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: theme,
|
||||||
|
home: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
drawer: NavigationDrawer(
|
||||||
|
indicatorColor: indicatorColor,
|
||||||
|
indicatorShape: indicatorShape,
|
||||||
|
children: <Widget>[
|
||||||
|
Text('Headline', style: theme.textTheme.bodyLarge),
|
||||||
|
const NavigationDrawerDestination(
|
||||||
|
icon: Icon(Icons.ac_unit),
|
||||||
|
label: Text('AC'),
|
||||||
|
),
|
||||||
|
const NavigationDrawerDestination(
|
||||||
|
icon: Icon(Icons.access_alarm),
|
||||||
|
label: Text('Alarm'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onDestinationSelected: (int i) { },
|
||||||
|
),
|
||||||
|
body: Container(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigationDrawer());
|
||||||
|
scaffoldKey.currentState!.openDrawer();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Test default indicator color and shape.
|
||||||
|
expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondaryContainer);
|
||||||
|
expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigationDrawer(indicatorColor: color, indicatorShape: shape));
|
||||||
|
|
||||||
|
// Test custom indicator color and shape.
|
||||||
|
expect(_getIndicatorDecoration(tester)?.color, color);
|
||||||
|
expect(_getIndicatorDecoration(tester)?.shape, shape);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildWidget(GlobalKey<ScaffoldState> scaffoldKey, Widget child) {
|
Widget _buildWidget(GlobalKey<ScaffoldState> scaffoldKey, Widget child) {
|
||||||
@ -242,7 +289,7 @@ Material _getMaterial(WidgetTester tester) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeDecoration? _indicator(WidgetTester tester) {
|
ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) {
|
||||||
return tester
|
return tester
|
||||||
.firstWidget<Container>(
|
.firstWidget<Container>(
|
||||||
find.descendant(
|
find.descendant(
|
||||||
|
@ -2846,6 +2846,50 @@ void main() {
|
|||||||
expect(transform.getColumn(0)[0], 1.0);
|
expect(transform.getColumn(0)[0], 1.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
|
||||||
|
final ThemeData theme = ThemeData(useMaterial3: true);
|
||||||
|
const Color color = Color(0xff0000ff);
|
||||||
|
const ShapeBorder shape = RoundedRectangleBorder();
|
||||||
|
|
||||||
|
Widget buildNavigationRail({Color? indicatorColor, ShapeBorder? indicatorShape}) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: theme,
|
||||||
|
home: Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
NavigationRail(
|
||||||
|
useIndicator: true,
|
||||||
|
indicatorColor: indicatorColor,
|
||||||
|
indicatorShape: indicatorShape,
|
||||||
|
selectedIndex: 0,
|
||||||
|
destinations: _destinations(),
|
||||||
|
),
|
||||||
|
const Expanded(
|
||||||
|
child: Text('body'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigationRail());
|
||||||
|
|
||||||
|
// Test default indicator color and shape.
|
||||||
|
expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondaryContainer);
|
||||||
|
expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigationRail(indicatorColor: color, indicatorShape: shape));
|
||||||
|
|
||||||
|
// Test custom indicator color and shape.
|
||||||
|
expect(_getIndicatorDecoration(tester)?.color, color);
|
||||||
|
expect(_getIndicatorDecoration(tester)?.shape, shape);
|
||||||
|
});
|
||||||
|
|
||||||
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 {
|
||||||
@ -4655,7 +4699,6 @@ void main() {
|
|||||||
final double updatedWidthRTL = tester.getSize(find.byType(NavigationRail)).width;
|
final double updatedWidthRTL = tester.getSize(find.byType(NavigationRail)).width;
|
||||||
expect(updatedWidthRTL, defaultWidth + safeAreaPadding);
|
expect(updatedWidthRTL, defaultWidth + safeAreaPadding);
|
||||||
});
|
});
|
||||||
|
|
||||||
}); // End Material 2 group
|
}); // End Material 2 group
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4878,3 +4921,12 @@ Widget _buildWidget(Widget child, {bool useMaterial3 = true, bool isRTL = false}
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) {
|
||||||
|
return tester.firstWidget<Container>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(FadeTransition),
|
||||||
|
matching: find.byType(Container),
|
||||||
|
),
|
||||||
|
).decoration as ShapeDecoration?;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user