Skip to content

Commit 888b141

Browse files
authored
fix: bottom navigation bar colors (#107924)
1 parent 29943e5 commit 888b141

File tree

2 files changed

+422
-26
lines changed

2 files changed

+422
-26
lines changed

packages/flutter/lib/src/material/bottom_navigation_bar.dart

Lines changed: 123 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ class BottomNavigationBar extends StatefulWidget {
154154
/// [selectedIconTheme] and [unselectedIconTheme], and both
155155
/// [IconThemeData.color] and [IconThemeData.size] must be set.
156156
///
157+
/// If [useLegacyColorScheme] is set to `false`
158+
/// [selectedIconTheme] values will be used instead of [iconSize] and [selectedItemColor] for selected icons.
159+
/// [unselectedIconTheme] values will be used instead of [iconSize] and [unselectedItemColor] for unselected icons.
160+
///
161+
///
157162
/// If both [selectedLabelStyle].fontSize and [selectedFontSize] are set,
158163
/// [selectedLabelStyle].fontSize will be used.
159164
///
@@ -193,6 +198,7 @@ class BottomNavigationBar extends StatefulWidget {
193198
this.mouseCursor,
194199
this.enableFeedback,
195200
this.landscapeLayout,
201+
this.useLegacyColorScheme = true,
196202
}) : assert(items != null),
197203
assert(items.length >= 2),
198204
assert(
@@ -381,6 +387,13 @@ class BottomNavigationBar extends StatefulWidget {
381387
/// orientation.
382388
final BottomNavigationBarLandscapeLayout? landscapeLayout;
383389

390+
/// This flag is controlling how [BottomNavigationBar] is going to use
391+
/// the colors provided by the [selectedIconTheme], [unselectedIconTheme],
392+
/// [selectedItemColor], [unselectedItemColor].
393+
/// The default value is `true` as the new theming logic is a breaking change.
394+
/// To opt-in the new theming logic set the flag to `false`
395+
final bool useLegacyColorScheme;
396+
384397
@override
385398
State<BottomNavigationBar> createState() => _BottomNavigationBarState();
386399
}
@@ -394,7 +407,8 @@ class _BottomNavigationTile extends StatelessWidget {
394407
this.animation,
395408
this.iconSize, {
396409
this.onTap,
397-
this.colorTween,
410+
this.labelColorTween,
411+
this.iconColorTween,
398412
this.flex,
399413
this.selected = false,
400414
required this.selectedLabelStyle,
@@ -420,7 +434,8 @@ class _BottomNavigationTile extends StatelessWidget {
420434
final Animation<double> animation;
421435
final double iconSize;
422436
final VoidCallback? onTap;
423-
final ColorTween? colorTween;
437+
final ColorTween? labelColorTween;
438+
final ColorTween? iconColorTween;
424439
final double? flex;
425440
final bool selected;
426441
final IconThemeData? selectedIconTheme;
@@ -523,7 +538,7 @@ class _BottomNavigationTile extends StatelessWidget {
523538
child: _Tile(
524539
layout: layout,
525540
icon: _TileIcon(
526-
colorTween: colorTween!,
541+
colorTween: iconColorTween!,
527542
animation: animation,
528543
iconSize: iconSize,
529544
selected: selected,
@@ -532,7 +547,7 @@ class _BottomNavigationTile extends StatelessWidget {
532547
unselectedIconTheme: unselectedIconTheme,
533548
),
534549
label: _Label(
535-
colorTween: colorTween!,
550+
colorTween: labelColorTween!,
536551
animation: animation,
537552
item: item,
538553
selectedLabelStyle: selectedLabelStyle,
@@ -910,24 +925,22 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
910925
return textStyle.fontSize == null ? textStyle.copyWith(fontSize: fontSize) : textStyle;
911926
}
912927

928+
// If [IconThemeData] is provided, it should be used.
929+
// Otherwise, the [IconThemeData]'s color should be selectedItemColor
930+
// or unselectedItemColor.
931+
static IconThemeData _effectiveIconTheme(IconThemeData? iconTheme, Color? itemColor) {
932+
// Prefer the iconTheme over itemColor if present.
933+
return iconTheme ?? IconThemeData(color: itemColor);
934+
}
935+
936+
913937
List<Widget> _createTiles(BottomNavigationBarLandscapeLayout layout) {
914938
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
915939
assert(localizations != null);
916940

917941
final ThemeData themeData = Theme.of(context);
918942
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
919943

920-
final TextStyle effectiveSelectedLabelStyle =
921-
_effectiveTextStyle(
922-
widget.selectedLabelStyle ?? bottomTheme.selectedLabelStyle,
923-
widget.selectedFontSize,
924-
);
925-
final TextStyle effectiveUnselectedLabelStyle =
926-
_effectiveTextStyle(
927-
widget.unselectedLabelStyle ?? bottomTheme.unselectedLabelStyle,
928-
widget.unselectedFontSize,
929-
);
930-
931944
final Color themeColor;
932945
switch (themeData.brightness) {
933946
case Brightness.light:
@@ -938,6 +951,39 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
938951
break;
939952
}
940953

954+
final TextStyle effectiveSelectedLabelStyle =
955+
_effectiveTextStyle(
956+
widget.selectedLabelStyle
957+
?? bottomTheme.selectedLabelStyle,
958+
widget.selectedFontSize,
959+
);
960+
961+
final TextStyle effectiveUnselectedLabelStyle =
962+
_effectiveTextStyle(
963+
widget.unselectedLabelStyle
964+
?? bottomTheme.unselectedLabelStyle,
965+
widget.unselectedFontSize,
966+
);
967+
968+
final IconThemeData effectiveSelectedIconTheme =
969+
_effectiveIconTheme(
970+
widget.selectedIconTheme
971+
?? bottomTheme.selectedIconTheme,
972+
widget.selectedItemColor
973+
?? bottomTheme.selectedItemColor
974+
?? themeColor
975+
);
976+
977+
final IconThemeData effectiveUnselectedIconTheme =
978+
_effectiveIconTheme(
979+
widget.unselectedIconTheme
980+
?? bottomTheme.unselectedIconTheme,
981+
widget.unselectedItemColor
982+
?? bottomTheme.unselectedItemColor
983+
?? themeData.unselectedWidgetColor
984+
);
985+
986+
941987
final ColorTween colorTween;
942988
switch (_effectiveType) {
943989
case BottomNavigationBarType.fixed:
@@ -963,6 +1009,64 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
9631009
break;
9641010
}
9651011

1012+
final ColorTween labelColorTween;
1013+
switch (_effectiveType) {
1014+
case BottomNavigationBarType.fixed:
1015+
labelColorTween = ColorTween(
1016+
begin: effectiveUnselectedLabelStyle.color
1017+
?? widget.unselectedItemColor
1018+
?? bottomTheme.unselectedItemColor
1019+
?? themeData.unselectedWidgetColor,
1020+
end: effectiveSelectedLabelStyle.color
1021+
?? widget.selectedItemColor
1022+
?? bottomTheme.selectedItemColor
1023+
?? widget.fixedColor
1024+
?? themeColor,
1025+
);
1026+
break;
1027+
case BottomNavigationBarType.shifting:
1028+
labelColorTween = ColorTween(
1029+
begin: effectiveUnselectedLabelStyle.color
1030+
?? widget.unselectedItemColor
1031+
?? bottomTheme.unselectedItemColor
1032+
?? themeData.colorScheme.surface,
1033+
end: effectiveSelectedLabelStyle.color
1034+
?? widget.selectedItemColor
1035+
?? bottomTheme.selectedItemColor
1036+
?? themeColor,
1037+
);
1038+
break;
1039+
}
1040+
1041+
final ColorTween iconColorTween;
1042+
switch (_effectiveType) {
1043+
case BottomNavigationBarType.fixed:
1044+
iconColorTween = ColorTween(
1045+
begin: effectiveSelectedIconTheme.color
1046+
?? widget.unselectedItemColor
1047+
?? bottomTheme.unselectedItemColor
1048+
?? themeData.unselectedWidgetColor,
1049+
end: effectiveUnselectedIconTheme.color
1050+
?? widget.selectedItemColor
1051+
?? bottomTheme.selectedItemColor
1052+
?? widget.fixedColor
1053+
?? themeColor,
1054+
);
1055+
break;
1056+
case BottomNavigationBarType.shifting:
1057+
iconColorTween = ColorTween(
1058+
begin: effectiveUnselectedIconTheme.color
1059+
?? widget.unselectedItemColor
1060+
?? bottomTheme.unselectedItemColor
1061+
?? themeData.colorScheme.surface,
1062+
end: effectiveSelectedIconTheme.color
1063+
?? widget.selectedItemColor
1064+
?? bottomTheme.selectedItemColor
1065+
?? themeColor,
1066+
);
1067+
break;
1068+
}
1069+
9661070
final List<Widget> tiles = <Widget>[];
9671071
for (int i = 0; i < widget.items.length; i++) {
9681072
final Set<MaterialState> states = <MaterialState>{
@@ -978,15 +1082,16 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
9781082
widget.items[i],
9791083
_animations[i],
9801084
widget.iconSize,
981-
selectedIconTheme: widget.selectedIconTheme ?? bottomTheme.selectedIconTheme,
982-
unselectedIconTheme: widget.unselectedIconTheme ?? bottomTheme.unselectedIconTheme,
1085+
selectedIconTheme: widget.useLegacyColorScheme ? widget.selectedIconTheme ?? bottomTheme.selectedIconTheme : effectiveSelectedIconTheme,
1086+
unselectedIconTheme: widget.useLegacyColorScheme ? widget.unselectedIconTheme ?? bottomTheme.unselectedIconTheme : effectiveUnselectedIconTheme,
9831087
selectedLabelStyle: effectiveSelectedLabelStyle,
9841088
unselectedLabelStyle: effectiveUnselectedLabelStyle,
9851089
enableFeedback: widget.enableFeedback ?? bottomTheme.enableFeedback ?? true,
9861090
onTap: () {
9871091
widget.onTap?.call(i);
9881092
},
989-
colorTween: colorTween,
1093+
labelColorTween: widget.useLegacyColorScheme ? colorTween : labelColorTween,
1094+
iconColorTween: widget.useLegacyColorScheme ? colorTween : iconColorTween,
9901095
flex: _evaluateFlex(_animations[i]),
9911096
selected: i == widget.currentIndex,
9921097
showSelectedLabels: widget.showSelectedLabels ?? bottomTheme.showSelectedLabels ?? true,

0 commit comments

Comments
 (0)