Unverified Commit e82454fb authored by MH Johnson's avatar MH Johnson Committed by GitHub

[Material] Added BottomNavigationBarTheme (#54714)

parent f050ee67
...@@ -28,6 +28,7 @@ export 'src/material/banner_theme.dart'; ...@@ -28,6 +28,7 @@ export 'src/material/banner_theme.dart';
export 'src/material/bottom_app_bar.dart'; export 'src/material/bottom_app_bar.dart';
export 'src/material/bottom_app_bar_theme.dart'; export 'src/material/bottom_app_bar_theme.dart';
export 'src/material/bottom_navigation_bar.dart'; export 'src/material/bottom_navigation_bar.dart';
export 'src/material/bottom_navigation_bar_theme.dart';
export 'src/material/bottom_sheet.dart'; export 'src/material/bottom_sheet.dart';
export 'src/material/bottom_sheet_theme.dart'; export 'src/material/bottom_sheet_theme.dart';
export 'src/material/button.dart'; export 'src/material/button.dart';
......
...@@ -8,7 +8,7 @@ import 'dart:math' as math; ...@@ -8,7 +8,7 @@ import 'dart:math' as math;
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:vector_math/vector_math_64.dart' show Vector3; import 'package:vector_math/vector_math_64.dart' show Vector3;
import 'colors.dart'; import 'bottom_navigation_bar_theme.dart';
import 'constants.dart'; import 'constants.dart';
import 'debug.dart'; import 'debug.dart';
import 'ink_well.dart'; import 'ink_well.dart';
...@@ -172,21 +172,21 @@ class BottomNavigationBar extends StatefulWidget { ...@@ -172,21 +172,21 @@ class BottomNavigationBar extends StatefulWidget {
@required this.items, @required this.items,
this.onTap, this.onTap,
this.currentIndex = 0, this.currentIndex = 0,
this.elevation = 8.0, this.elevation,
BottomNavigationBarType type, this.type,
Color fixedColor, Color fixedColor,
this.backgroundColor, this.backgroundColor,
this.iconSize = 24.0, this.iconSize = 24.0,
Color selectedItemColor, Color selectedItemColor,
this.unselectedItemColor, this.unselectedItemColor,
this.selectedIconTheme = const IconThemeData(), this.selectedIconTheme,
this.unselectedIconTheme = const IconThemeData(), this.unselectedIconTheme,
this.selectedFontSize = 14.0, this.selectedFontSize = 14.0,
this.unselectedFontSize = 12.0, this.unselectedFontSize = 12.0,
this.selectedLabelStyle, this.selectedLabelStyle,
this.unselectedLabelStyle, this.unselectedLabelStyle,
this.showSelectedLabels = true, this.showSelectedLabels = true,
bool showUnselectedLabels, this.showUnselectedLabels,
}) : assert(items != null), }) : assert(items != null),
assert(items.length >= 2), assert(items.length >= 2),
assert( assert(
...@@ -194,7 +194,7 @@ class BottomNavigationBar extends StatefulWidget { ...@@ -194,7 +194,7 @@ class BottomNavigationBar extends StatefulWidget {
'Every item must have a non-null title', 'Every item must have a non-null title',
), ),
assert(0 <= currentIndex && currentIndex < items.length), assert(0 <= currentIndex && currentIndex < items.length),
assert(elevation != null && elevation >= 0.0), assert(elevation == null || elevation >= 0.0),
assert(iconSize != null && iconSize >= 0.0), assert(iconSize != null && iconSize >= 0.0),
assert( assert(
selectedItemColor == null || fixedColor == null, selectedItemColor == null || fixedColor == null,
...@@ -203,9 +203,7 @@ class BottomNavigationBar extends StatefulWidget { ...@@ -203,9 +203,7 @@ class BottomNavigationBar extends StatefulWidget {
assert(selectedFontSize != null && selectedFontSize >= 0.0), assert(selectedFontSize != null && selectedFontSize >= 0.0),
assert(unselectedFontSize != null && unselectedFontSize >= 0.0), assert(unselectedFontSize != null && unselectedFontSize >= 0.0),
assert(showSelectedLabels != null), assert(showSelectedLabels != null),
type = _type(type, items),
selectedItemColor = selectedItemColor ?? fixedColor, selectedItemColor = selectedItemColor ?? fixedColor,
showUnselectedLabels = showUnselectedLabels ?? _defaultShowUnselected(_type(type, items)),
super(key: key); super(key: key);
/// Defines the appearance of the button items that are arrayed within the /// Defines the appearance of the button items that are arrayed within the
...@@ -316,37 +314,6 @@ class BottomNavigationBar extends StatefulWidget { ...@@ -316,37 +314,6 @@ class BottomNavigationBar extends StatefulWidget {
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s. /// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
final bool showSelectedLabels; final bool showSelectedLabels;
// Used by the [BottomNavigationBar] constructor to set the [type] parameter.
//
// If type is provided, it is returned. Otherwise,
// [BottomNavigationBarType.fixed] is used for 3 or fewer items, and
// [BottomNavigationBarType.shifting] is used for 4+ items.
static BottomNavigationBarType _type(
BottomNavigationBarType type,
List<BottomNavigationBarItem> items,
) {
if (type != null) {
return type;
}
return items.length <= 3 ? BottomNavigationBarType.fixed : BottomNavigationBarType.shifting;
}
// Used by the [BottomNavigationBar] constructor to set the [showUnselected]
// parameter.
//
// Unselected labels are shown by default for [BottomNavigationBarType.fixed],
// and hidden by default for [BottomNavigationBarType.shifting].
static bool _defaultShowUnselected(BottomNavigationBarType type) {
switch (type) {
case BottomNavigationBarType.shifting:
return false;
case BottomNavigationBarType.fixed:
return true;
}
assert(false);
return false;
}
@override @override
_BottomNavigationBarState createState() => _BottomNavigationBarState(); _BottomNavigationBarState createState() => _BottomNavigationBarState();
} }
...@@ -401,10 +368,17 @@ class _BottomNavigationTile extends StatelessWidget { ...@@ -401,10 +368,17 @@ class _BottomNavigationTile extends StatelessWidget {
// (which is an integer) by a large number. // (which is an integer) by a large number.
int size; int size;
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
final double selectedFontSize = selectedLabelStyle.fontSize; final double selectedFontSize = selectedLabelStyle.fontSize;
final double selectedIconSize = selectedIconTheme?.size ?? iconSize; final double selectedIconSize = selectedIconTheme?.size
final double unselectedIconSize = unselectedIconTheme?.size ?? iconSize; ?? bottomTheme?.selectedIconTheme?.size
?? iconSize;
final double unselectedIconSize = unselectedIconTheme?.size
?? bottomTheme?.unselectedIconTheme?.size
?? iconSize;
// The amount that the selected icon is bigger than the unselected icons, // The amount that the selected icon is bigger than the unselected icons,
// (or zero if the selected icon is not bigger than the unselected icons). // (or zero if the selected icon is not bigger than the unselected icons).
final double selectedIconDiff = math.max(selectedIconSize - unselectedIconSize, 0); final double selectedIconDiff = math.max(selectedIconSize - unselectedIconSize, 0);
...@@ -491,17 +465,17 @@ class _BottomNavigationTile extends StatelessWidget { ...@@ -491,17 +465,17 @@ class _BottomNavigationTile extends StatelessWidget {
iconSize: iconSize, iconSize: iconSize,
selected: selected, selected: selected,
item: item, item: item,
selectedIconTheme: selectedIconTheme, selectedIconTheme: selectedIconTheme ?? bottomTheme.selectedIconTheme,
unselectedIconTheme: unselectedIconTheme, unselectedIconTheme: unselectedIconTheme ?? bottomTheme.unselectedIconTheme,
), ),
_Label( _Label(
colorTween: colorTween, colorTween: colorTween,
animation: animation, animation: animation,
item: item, item: item,
selectedLabelStyle: selectedLabelStyle, selectedLabelStyle: selectedLabelStyle ?? bottomTheme.selectedLabelStyle,
unselectedLabelStyle: unselectedLabelStyle, unselectedLabelStyle: unselectedLabelStyle ?? bottomTheme.unselectedLabelStyle,
showSelectedLabels: showSelectedLabels, showSelectedLabels: showSelectedLabels ?? bottomTheme.showUnselectedLabels,
showUnselectedLabels: showUnselectedLabels, showUnselectedLabels: showUnselectedLabels ?? bottomTheme.showUnselectedLabels,
), ),
], ],
), ),
...@@ -693,6 +667,33 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -693,6 +667,33 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
_backgroundColor = widget.items[widget.currentIndex].backgroundColor; _backgroundColor = widget.items[widget.currentIndex].backgroundColor;
} }
// Computes the default value for the [type] parameter.
//
// If type is provided, it is returned. Next, if the bottom navigation bar
// theme provides a type, it is used. Finally, the default behavior will be
// [BottomNavigationBarType.fixed] for 3 or fewer items, and
// [BottomNavigationBarType.shifting] is used for 4+ items.
BottomNavigationBarType get _effectiveType {
return widget.type
?? BottomNavigationBarTheme.of(context).type
?? (widget.items.length <= 3 ? BottomNavigationBarType.fixed : BottomNavigationBarType.shifting);
}
// Computes the default value for the [showUnselected] parameter.
//
// Unselected labels are shown by default for [BottomNavigationBarType.fixed],
// and hidden by default for [BottomNavigationBarType.shifting].
bool get _defaultShowUnselected {
switch (_effectiveType) {
case BottomNavigationBarType.shifting:
return false;
case BottomNavigationBarType.fixed:
return true;
}
assert(false);
return false;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
...@@ -757,7 +758,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -757,7 +758,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
} }
if (widget.currentIndex != oldWidget.currentIndex) { if (widget.currentIndex != oldWidget.currentIndex) {
switch (widget.type) { switch (_effectiveType) {
case BottomNavigationBarType.fixed: case BottomNavigationBarType.fixed:
break; break;
case BottomNavigationBarType.shifting: case BottomNavigationBarType.shifting:
...@@ -785,11 +786,18 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -785,11 +786,18 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
assert(localizations != null); assert(localizations != null);
final ThemeData themeData = Theme.of(context); final ThemeData themeData = Theme.of(context);
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
final TextStyle effectiveSelectedLabelStyle = final TextStyle effectiveSelectedLabelStyle =
_effectiveTextStyle(widget.selectedLabelStyle, widget.selectedFontSize); _effectiveTextStyle(
widget.selectedLabelStyle ?? bottomTheme.selectedLabelStyle,
widget.selectedFontSize,
);
final TextStyle effectiveUnselectedLabelStyle = final TextStyle effectiveUnselectedLabelStyle =
_effectiveTextStyle(widget.unselectedLabelStyle, widget.unselectedFontSize); _effectiveTextStyle(
widget.unselectedLabelStyle ?? bottomTheme.unselectedLabelStyle,
widget.unselectedFontSize,
);
Color themeColor; Color themeColor;
switch (themeData.brightness) { switch (themeData.brightness) {
...@@ -802,17 +810,26 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -802,17 +810,26 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
} }
ColorTween colorTween; ColorTween colorTween;
switch (widget.type) { switch (_effectiveType) {
case BottomNavigationBarType.fixed: case BottomNavigationBarType.fixed:
colorTween = ColorTween( colorTween = ColorTween(
begin: widget.unselectedItemColor ?? themeData.textTheme.caption.color, begin: widget.unselectedItemColor
end: widget.selectedItemColor ?? widget.fixedColor ?? themeColor, ?? bottomTheme.unselectedItemColor
?? themeData.textTheme.caption.color,
end: widget.selectedItemColor
?? bottomTheme.selectedItemColor
?? widget.fixedColor
?? themeColor,
); );
break; break;
case BottomNavigationBarType.shifting: case BottomNavigationBarType.shifting:
colorTween = ColorTween( colorTween = ColorTween(
begin: widget.unselectedItemColor ?? Colors.white, begin: widget.unselectedItemColor
end: widget.selectedItemColor ?? Colors.white, ?? bottomTheme.unselectedItemColor
?? themeData.colorScheme.surface,
end: widget.selectedItemColor
?? bottomTheme.selectedItemColor
?? themeData.colorScheme.surface,
); );
break; break;
} }
...@@ -820,12 +837,12 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -820,12 +837,12 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
final List<Widget> tiles = <Widget>[]; final List<Widget> tiles = <Widget>[];
for (int i = 0; i < widget.items.length; i++) { for (int i = 0; i < widget.items.length; i++) {
tiles.add(_BottomNavigationTile( tiles.add(_BottomNavigationTile(
widget.type, _effectiveType,
widget.items[i], widget.items[i],
_animations[i], _animations[i],
widget.iconSize, widget.iconSize,
selectedIconTheme: widget.selectedIconTheme, selectedIconTheme: widget.selectedIconTheme ?? bottomTheme.selectedIconTheme,
unselectedIconTheme: widget.unselectedIconTheme, unselectedIconTheme: widget.unselectedIconTheme ?? bottomTheme.unselectedIconTheme,
selectedLabelStyle: effectiveSelectedLabelStyle, selectedLabelStyle: effectiveSelectedLabelStyle,
unselectedLabelStyle: effectiveUnselectedLabelStyle, unselectedLabelStyle: effectiveUnselectedLabelStyle,
onTap: () { onTap: () {
...@@ -835,8 +852,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -835,8 +852,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
colorTween: colorTween, colorTween: colorTween,
flex: _evaluateFlex(_animations[i]), flex: _evaluateFlex(_animations[i]),
selected: i == widget.currentIndex, selected: i == widget.currentIndex,
showSelectedLabels: widget.showSelectedLabels, showSelectedLabels: widget.showSelectedLabels ?? bottomTheme.showSelectedLabels,
showUnselectedLabels: widget.showUnselectedLabels, showUnselectedLabels: widget.showUnselectedLabels ?? bottomTheme.showUnselectedLabels ?? _defaultShowUnselected,
indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length), indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length),
)); ));
} }
...@@ -859,12 +876,14 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -859,12 +876,14 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
assert(debugCheckHasMediaQuery(context)); assert(debugCheckHasMediaQuery(context));
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
// Labels apply up to _bottomMargin padding. Remainder is media padding. // Labels apply up to _bottomMargin padding. Remainder is media padding.
final double additionalBottomPadding = math.max(MediaQuery.of(context).padding.bottom - widget.selectedFontSize / 2.0, 0.0); final double additionalBottomPadding = math.max(MediaQuery.of(context).padding.bottom - widget.selectedFontSize / 2.0, 0.0);
Color backgroundColor; Color backgroundColor;
switch (widget.type) { switch (_effectiveType) {
case BottomNavigationBarType.fixed: case BottomNavigationBarType.fixed:
backgroundColor = widget.backgroundColor; backgroundColor = widget.backgroundColor ?? bottomTheme.backgroundColor;
break; break;
case BottomNavigationBarType.shifting: case BottomNavigationBarType.shifting:
backgroundColor = _backgroundColor; backgroundColor = _backgroundColor;
...@@ -873,7 +892,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr ...@@ -873,7 +892,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
return Semantics( return Semantics(
explicitChildNodes: true, explicitChildNodes: true,
child: Material( child: Material(
elevation: widget.elevation, elevation: widget.elevation ?? bottomTheme.elevation ?? 8.0,
color: backgroundColor, color: backgroundColor,
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints(minHeight: kBottomNavigationBarHeight + additionalBottomPadding), constraints: BoxConstraints(minHeight: kBottomNavigationBarHeight + additionalBottomPadding),
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show lerpDouble;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'bottom_navigation_bar.dart';
import 'theme.dart';
/// Defines default property values for descendant [BottomNavigationBar]
/// widgets.
///
/// Descendant widgets obtain the current [BottomNavigationBarThemeData] object
/// using `BottomNavigationBarTheme.of(context)`. Instances of
/// [BottomNavigationBarThemeData] can be customized with
/// [BottomNavigationBarThemeData.copyWith].
///
/// Typically a [BottomNavigationBarThemeData] is specified as part of the
/// overall [Theme] with [ThemeData.bottomNavigationBarTheme].
///
/// All [BottomNavigationBarThemeData] properties are `null` by default. When
/// null, the [BottomNavigationBar]'s build method provides defaults.
///
/// See also:
///
/// * [ThemeData], which describes the overall theme information for the
/// application.
@immutable
class BottomNavigationBarThemeData with Diagnosticable {
/// Creates a theme that can be used for [ThemeData.BottomNavigationBarTheme].
const BottomNavigationBarThemeData({
this.backgroundColor,
this.elevation,
this.selectedIconTheme,
this.unselectedIconTheme,
this.selectedItemColor,
this.unselectedItemColor,
this.selectedLabelStyle,
this.unselectedLabelStyle,
this.showSelectedLabels,
this.showUnselectedLabels,
this.type,
});
/// The color of the [BottomNavigationBar] itself.
///
/// See [BottomNavigationBar.backgroundColor].
final Color backgroundColor;
/// The z-coordinate of the [BottomNavigationBar].
///
/// See [BottomNavigationBar.elevation].
final double elevation;
/// The size, opacity, and color of the icon in the currently selected
/// [BottomNavigationBarItem.icon].
///
/// See [BottomNavigationBar.selectedIconTheme].
final IconThemeData selectedIconTheme;
/// The size, opacity, and color of the icon in the currently unselected
/// [BottomNavigationBarItem.icon]s.
///
/// See [BottomNavigationBar.unselectedIconTheme].
final IconThemeData unselectedIconTheme;
/// The color of the selected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.label].
///
/// See [BottomNavigationBar.selectedItemColor].
final Color selectedItemColor;
/// The color of the unselected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.label]s.
///
/// See [BottomNavigationBar.unselectedItemColor].
final Color unselectedItemColor;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
/// selected.
///
/// See [BottomNavigationBar.selectedLabelStyle].
final TextStyle selectedLabelStyle;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
/// selected.
///
/// See [BottomNavigationBar.unselectedLabelStyle].
final TextStyle unselectedLabelStyle;
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
///
/// See [BottomNavigationBar.showSelectedLabels].
final bool showSelectedLabels;
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
///
/// See [BottomNavigationBar.showUnselectedLabels].
final bool showUnselectedLabels;
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// See [BottomNavigationBar.type].
final BottomNavigationBarType type;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
BottomNavigationBarThemeData copyWith({
Color backgroundColor,
double elevation,
IconThemeData selectedIconTheme,
IconThemeData unselectedIconTheme,
Color selectedItemColor,
Color unselectedItemColor,
TextStyle selectedLabelStyle,
TextStyle unselectedLabelStyle,
bool showSelectedLabels,
bool showUnselectedLabels,
BottomNavigationBarType type,
}) {
return BottomNavigationBarThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor,
elevation: elevation ?? this.elevation,
selectedIconTheme: selectedIconTheme ?? this.selectedIconTheme,
unselectedIconTheme: unselectedIconTheme ?? this.unselectedIconTheme,
selectedItemColor: selectedItemColor ?? this.selectedItemColor,
unselectedItemColor: unselectedItemColor ?? this.unselectedItemColor,
selectedLabelStyle: selectedLabelStyle ?? this.selectedLabelStyle,
unselectedLabelStyle: unselectedLabelStyle ?? this.unselectedLabelStyle,
showSelectedLabels: showSelectedLabels ?? this.showSelectedLabels,
showUnselectedLabels: showUnselectedLabels ?? this.showUnselectedLabels,
type: type ?? this.type,
);
}
/// Linearly interpolate between two [BottomNavigationBarThemeData].
///
/// The argument `t` must not be null.
///
/// {@macro dart.ui.shadow.lerp}
static BottomNavigationBarThemeData lerp(BottomNavigationBarThemeData a, BottomNavigationBarThemeData b, double t) {
assert(t != null);
return BottomNavigationBarThemeData(
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t),
selectedIconTheme: IconThemeData.lerp(a?.selectedIconTheme, b?.selectedIconTheme, t),
unselectedIconTheme: IconThemeData.lerp(a?.unselectedIconTheme, b?.unselectedIconTheme, t),
selectedItemColor: Color.lerp(a?.selectedItemColor, b?.selectedItemColor, t),
unselectedItemColor: Color.lerp(a?.unselectedItemColor, b?.unselectedItemColor, t),
selectedLabelStyle: TextStyle.lerp(a?.selectedLabelStyle, b?.selectedLabelStyle, t),
unselectedLabelStyle: TextStyle.lerp(a?.unselectedLabelStyle, b?.unselectedLabelStyle, t),
showSelectedLabels: t < 0.5 ? a?.showSelectedLabels : b?.showSelectedLabels,
showUnselectedLabels: t < 0.5 ? a?.showUnselectedLabels : b?.showUnselectedLabels,
type: t < 0.5 ? a?.type : b?.type,
);
}
@override
int get hashCode {
return hashValues(
backgroundColor,
elevation,
selectedIconTheme,
unselectedIconTheme,
selectedItemColor,
unselectedItemColor,
selectedLabelStyle,
unselectedLabelStyle,
showSelectedLabels,
showUnselectedLabels,
type,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other))
return true;
if (other.runtimeType != runtimeType)
return false;
return other is BottomNavigationBarThemeData
&& other.backgroundColor == backgroundColor
&& other.elevation == elevation
&& other.selectedIconTheme == selectedIconTheme
&& other.unselectedIconTheme == unselectedIconTheme
&& other.selectedItemColor == selectedItemColor
&& other.unselectedItemColor == unselectedItemColor
&& other.selectedLabelStyle == selectedLabelStyle
&& other.unselectedLabelStyle == unselectedLabelStyle
&& other.showSelectedLabels == showSelectedLabels
&& other.showUnselectedLabels == showUnselectedLabels
&& other.type == type;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
properties.add(DiagnosticsProperty<IconThemeData>('selectedIconTheme', selectedIconTheme, defaultValue: null));
properties.add(DiagnosticsProperty<IconThemeData>('unselectedIconTheme', unselectedIconTheme, defaultValue: null));
properties.add(ColorProperty('selectedItemColor', selectedItemColor, defaultValue: null));
properties.add(ColorProperty('unselectedItemColor', unselectedItemColor, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('selectedLabelStyle', selectedLabelStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('unselectedLabelStyle', unselectedLabelStyle, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('showSelectedLabels', showSelectedLabels, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('showUnselectedLabels', showUnselectedLabels, defaultValue: null));
properties.add(DiagnosticsProperty<BottomNavigationBarType>('type', type, defaultValue: null));
}
}
/// Applies a bottom navigation bar theme to descendant [BottomNavigationBar]
/// widgets.
///
/// Descendant widgets obtain the current theme's [BottomNavigationBarTheme]
/// object using [BottomNavigationBarTheme.of]. When a widget uses
/// [BottomNavigationBarTheme.of], it is automatically rebuilt if the theme
/// later changes.
///
/// A bottom navigation theme can be specified as part of the overall Material
/// theme using [ThemeData.bottomNavigationBarTheme].
///
/// See also:
///
/// * [BottomNavigationBarThemeData], which describes the actual configuration
/// of a bottom navigation bar theme.
class BottomNavigationBarTheme extends InheritedWidget {
/// Constructs a bottom navigation bar theme that configures all descendant
/// [BottomNavigationBar] widgets.
///
/// The [data] must not be null.
const BottomNavigationBarTheme({
Key key,
@required this.data,
Widget child,
}) : assert(data != null), super(key: key, child: child);
/// The properties used for all descendant [BottomNavigationBar] widgets.
final BottomNavigationBarThemeData data;
/// Returns the configuration [data] from the closest
/// [BottomNavigationBarTheme] ancestor. If there is no ancestor, it returns
/// [ThemeData.bottomNavigationBarTheme]. Applications can assume that the
/// returned value will not be null.
///
/// Typical usage is as follows:
///
/// ```dart
/// BottomNavigationBarThemeData theme = BottomNavigationBarTheme.of(context);
/// ```
static BottomNavigationBarThemeData of(BuildContext context) {
final BottomNavigationBarTheme bottomNavTheme = context.dependOnInheritedWidgetOfExactType<BottomNavigationBarTheme>();
return bottomNavTheme?.data ?? Theme.of(context).bottomNavigationBarTheme;
}
@override
bool updateShouldNotify(BottomNavigationBarTheme oldWidget) => data != oldWidget.data;
}
...@@ -12,6 +12,7 @@ import 'package:flutter/widgets.dart'; ...@@ -12,6 +12,7 @@ import 'package:flutter/widgets.dart';
import 'app_bar_theme.dart'; import 'app_bar_theme.dart';
import 'banner_theme.dart'; import 'banner_theme.dart';
import 'bottom_app_bar_theme.dart'; import 'bottom_app_bar_theme.dart';
import 'bottom_navigation_bar_theme.dart';
import 'bottom_sheet_theme.dart'; import 'bottom_sheet_theme.dart';
import 'button_bar_theme.dart'; import 'button_bar_theme.dart';
import 'button_theme.dart'; import 'button_theme.dart';
...@@ -266,6 +267,7 @@ class ThemeData with Diagnosticable { ...@@ -266,6 +267,7 @@ class ThemeData with Diagnosticable {
MaterialBannerThemeData bannerTheme, MaterialBannerThemeData bannerTheme,
DividerThemeData dividerTheme, DividerThemeData dividerTheme,
ButtonBarThemeData buttonBarTheme, ButtonBarThemeData buttonBarTheme,
BottomNavigationBarThemeData bottomNavigationBarTheme,
}) { }) {
brightness ??= Brightness.light; brightness ??= Brightness.light;
final bool isDark = brightness == Brightness.dark; final bool isDark = brightness == Brightness.dark;
...@@ -374,6 +376,7 @@ class ThemeData with Diagnosticable { ...@@ -374,6 +376,7 @@ class ThemeData with Diagnosticable {
bannerTheme ??= const MaterialBannerThemeData(); bannerTheme ??= const MaterialBannerThemeData();
dividerTheme ??= const DividerThemeData(); dividerTheme ??= const DividerThemeData();
buttonBarTheme ??= const ButtonBarThemeData(); buttonBarTheme ??= const ButtonBarThemeData();
bottomNavigationBarTheme ??= const BottomNavigationBarThemeData();
return ThemeData.raw( return ThemeData.raw(
brightness: brightness, brightness: brightness,
...@@ -440,6 +443,7 @@ class ThemeData with Diagnosticable { ...@@ -440,6 +443,7 @@ class ThemeData with Diagnosticable {
bannerTheme: bannerTheme, bannerTheme: bannerTheme,
dividerTheme: dividerTheme, dividerTheme: dividerTheme,
buttonBarTheme: buttonBarTheme, buttonBarTheme: buttonBarTheme,
bottomNavigationBarTheme: bottomNavigationBarTheme,
); );
} }
...@@ -518,6 +522,7 @@ class ThemeData with Diagnosticable { ...@@ -518,6 +522,7 @@ class ThemeData with Diagnosticable {
@required this.bannerTheme, @required this.bannerTheme,
@required this.dividerTheme, @required this.dividerTheme,
@required this.buttonBarTheme, @required this.buttonBarTheme,
@required this.bottomNavigationBarTheme,
}) : assert(brightness != null), }) : assert(brightness != null),
assert(visualDensity != null), assert(visualDensity != null),
assert(primaryColor != null), assert(primaryColor != null),
...@@ -578,7 +583,8 @@ class ThemeData with Diagnosticable { ...@@ -578,7 +583,8 @@ class ThemeData with Diagnosticable {
assert(popupMenuTheme != null), assert(popupMenuTheme != null),
assert(bannerTheme != null), assert(bannerTheme != null),
assert(dividerTheme != null), assert(dividerTheme != null),
assert(buttonBarTheme != null); assert(buttonBarTheme != null),
assert(bottomNavigationBarTheme != null);
/// Create a [ThemeData] based on the colors in the given [colorScheme] and /// Create a [ThemeData] based on the colors in the given [colorScheme] and
/// text styles of the optional [textTheme]. /// text styles of the optional [textTheme].
...@@ -1025,6 +1031,10 @@ class ThemeData with Diagnosticable { ...@@ -1025,6 +1031,10 @@ class ThemeData with Diagnosticable {
/// A theme for customizing the appearance and layout of [ButtonBar] widgets. /// A theme for customizing the appearance and layout of [ButtonBar] widgets.
final ButtonBarThemeData buttonBarTheme; final ButtonBarThemeData buttonBarTheme;
/// A theme for customizing the appearance and layout of [BottomNavigationBar]
/// widgets.
final BottomNavigationBarThemeData bottomNavigationBarTheme;
/// Creates a copy of this theme but with the given fields replaced with the new values. /// Creates a copy of this theme but with the given fields replaced with the new values.
ThemeData copyWith({ ThemeData copyWith({
Brightness brightness, Brightness brightness,
...@@ -1091,6 +1101,7 @@ class ThemeData with Diagnosticable { ...@@ -1091,6 +1101,7 @@ class ThemeData with Diagnosticable {
MaterialBannerThemeData bannerTheme, MaterialBannerThemeData bannerTheme,
DividerThemeData dividerTheme, DividerThemeData dividerTheme,
ButtonBarThemeData buttonBarTheme, ButtonBarThemeData buttonBarTheme,
BottomNavigationBarThemeData bottomNavigationBarTheme,
}) { }) {
cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault();
return ThemeData.raw( return ThemeData.raw(
...@@ -1158,6 +1169,7 @@ class ThemeData with Diagnosticable { ...@@ -1158,6 +1169,7 @@ class ThemeData with Diagnosticable {
bannerTheme: bannerTheme ?? this.bannerTheme, bannerTheme: bannerTheme ?? this.bannerTheme,
dividerTheme: dividerTheme ?? this.dividerTheme, dividerTheme: dividerTheme ?? this.dividerTheme,
buttonBarTheme: buttonBarTheme ?? this.buttonBarTheme, buttonBarTheme: buttonBarTheme ?? this.buttonBarTheme,
bottomNavigationBarTheme: bottomNavigationBarTheme ?? this.bottomNavigationBarTheme,
); );
} }
...@@ -1303,6 +1315,7 @@ class ThemeData with Diagnosticable { ...@@ -1303,6 +1315,7 @@ class ThemeData with Diagnosticable {
bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t), bannerTheme: MaterialBannerThemeData.lerp(a.bannerTheme, b.bannerTheme, t),
dividerTheme: DividerThemeData.lerp(a.dividerTheme, b.dividerTheme, t), dividerTheme: DividerThemeData.lerp(a.dividerTheme, b.dividerTheme, t),
buttonBarTheme: ButtonBarThemeData.lerp(a.buttonBarTheme, b.buttonBarTheme, t), buttonBarTheme: ButtonBarThemeData.lerp(a.buttonBarTheme, b.buttonBarTheme, t),
bottomNavigationBarTheme: BottomNavigationBarThemeData.lerp(a.bottomNavigationBarTheme, b.bottomNavigationBarTheme, t),
); );
} }
...@@ -1375,7 +1388,8 @@ class ThemeData with Diagnosticable { ...@@ -1375,7 +1388,8 @@ class ThemeData with Diagnosticable {
&& other.popupMenuTheme == popupMenuTheme && other.popupMenuTheme == popupMenuTheme
&& other.bannerTheme == bannerTheme && other.bannerTheme == bannerTheme
&& other.dividerTheme == dividerTheme && other.dividerTheme == dividerTheme
&& other.buttonBarTheme == buttonBarTheme; && other.buttonBarTheme == buttonBarTheme
&& other.bottomNavigationBarTheme == bottomNavigationBarTheme;
} }
@override @override
...@@ -1448,6 +1462,7 @@ class ThemeData with Diagnosticable { ...@@ -1448,6 +1462,7 @@ class ThemeData with Diagnosticable {
bannerTheme, bannerTheme,
dividerTheme, dividerTheme,
buttonBarTheme, buttonBarTheme,
bottomNavigationBarTheme,
]; ];
return hashList(values); return hashList(values);
} }
...@@ -1516,6 +1531,7 @@ class ThemeData with Diagnosticable { ...@@ -1516,6 +1531,7 @@ class ThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<MaterialBannerThemeData>('bannerTheme', bannerTheme, defaultValue: defaultData.bannerTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty<MaterialBannerThemeData>('bannerTheme', bannerTheme, defaultValue: defaultData.bannerTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<DividerThemeData>('dividerTheme', dividerTheme, defaultValue: defaultData.dividerTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty<DividerThemeData>('dividerTheme', dividerTheme, defaultValue: defaultData.dividerTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<ButtonBarThemeData>('buttonBarTheme', buttonBarTheme, defaultValue: defaultData.buttonBarTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty<ButtonBarThemeData>('buttonBarTheme', buttonBarTheme, defaultValue: defaultData.buttonBarTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<BottomNavigationBarThemeData>('bottomNavigationBarTheme', bottomNavigationBarTheme, defaultValue: defaultData.bottomNavigationBarTheme, level: DiagnosticLevel.debug));
} }
} }
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:vector_math/vector_math_64.dart' show Vector3;
void main() {
test('BottomNavigationBarThemeData copyWith, ==, hashCode basics', () {
expect(const BottomNavigationBarThemeData(), const BottomNavigationBarThemeData().copyWith());
expect(const BottomNavigationBarThemeData().hashCode, const BottomNavigationBarThemeData().copyWith().hashCode);
});
test('BottomNavigationBarThemeData defaults', () {
const BottomNavigationBarThemeData themeData = BottomNavigationBarThemeData();
expect(themeData.backgroundColor, null);
expect(themeData.elevation, null);
expect(themeData.selectedIconTheme, null);
expect(themeData.unselectedIconTheme, null);
expect(themeData.selectedItemColor, null);
expect(themeData.unselectedItemColor, null);
expect(themeData.selectedLabelStyle, null);
expect(themeData.unselectedLabelStyle, null);
expect(themeData.showSelectedLabels, null);
expect(themeData.showUnselectedLabels, null);
expect(themeData.type, null);
const BottomNavigationBarTheme theme = BottomNavigationBarTheme(data: BottomNavigationBarThemeData());
expect(theme.data.backgroundColor, null);
expect(theme.data.elevation, null);
expect(theme.data.selectedIconTheme, null);
expect(theme.data.unselectedIconTheme, null);
expect(theme.data.selectedItemColor, null);
expect(theme.data.unselectedItemColor, null);
expect(theme.data.selectedLabelStyle, null);
expect(theme.data.unselectedLabelStyle, null);
expect(theme.data.showSelectedLabels, null);
expect(theme.data.showUnselectedLabels, null);
expect(theme.data.type, null);
});
testWidgets('Default BottomNavigationBarThemeData debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const BottomNavigationBarThemeData().debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
testWidgets('BottomNavigationBarThemeData implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const BottomNavigationBarThemeData(
backgroundColor: Color(0xfffffff0),
elevation: 10.0,
selectedIconTheme: IconThemeData(size: 1.0),
unselectedIconTheme: IconThemeData(size: 2.0),
selectedItemColor: Color(0xfffffff1),
unselectedItemColor: Color(0xfffffff2),
selectedLabelStyle: TextStyle(fontSize: 3.0),
unselectedLabelStyle: TextStyle(fontSize: 4.0),
showSelectedLabels: true,
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
).debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description[0], 'backgroundColor: Color(0xfffffff0)');
expect(description[1], 'elevation: 10.0');
// Ignore instance address for IconThemeData.
expect(description[2].contains('selectedIconTheme: IconThemeData'), isTrue);
expect(description[2].contains('(size: 1.0)'), isTrue);
expect(description[3].contains('unselectedIconTheme: IconThemeData'), isTrue);
expect(description[3].contains('(size: 2.0)'), isTrue);
expect(description[4], 'selectedItemColor: Color(0xfffffff1)');
expect(description[5], 'unselectedItemColor: Color(0xfffffff2)');
expect(description[6], 'selectedLabelStyle: TextStyle(inherit: true, size: 3.0)');
expect(description[7], 'unselectedLabelStyle: TextStyle(inherit: true, size: 4.0)');
expect(description[8], 'showSelectedLabels: true');
expect(description[9], 'showUnselectedLabels: true');
expect(description[10], 'type: BottomNavigationBarType.fixed');
});
testWidgets('BottomNavigationBar is themable', (WidgetTester tester) async {
const Color backgroundColor = Color(0xFF000001);
const Color selectedItemColor = Color(0xFF000002);
const Color unselectedItemColor = Color(0xFF000003);
const IconThemeData selectedIconTheme = IconThemeData(size: 10);
const IconThemeData unselectedIconTheme = IconThemeData(size: 11);
const TextStyle selectedTextStyle = TextStyle(fontSize: 22);
const TextStyle unselectedTextStyle = TextStyle(fontSize: 21);
const double elevation = 9.0;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: backgroundColor,
selectedItemColor: selectedItemColor,
unselectedItemColor: unselectedItemColor,
selectedIconTheme: selectedIconTheme,
unselectedIconTheme: unselectedIconTheme,
elevation: elevation,
showUnselectedLabels: true,
showSelectedLabels: true,
type: BottomNavigationBarType.fixed,
selectedLabelStyle: selectedTextStyle,
unselectedLabelStyle: unselectedTextStyle,
),
),
home: Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.ac_unit),
title: Text('AC'),
),
BottomNavigationBarItem(
icon: Icon(Icons.access_alarm),
title: Text('Alarm'),
),
],
),
),
),
);
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style;
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize);
// Unselected label has a font size of 22 but is scaled down to be font size 21.
expect(
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize / selectedTextStyle.fontSize))),
);
expect(selectedIcon.color, equals(selectedItemColor));
expect(selectedIcon.fontSize, equals(selectedIconTheme.size));
expect(unselectedIcon.color, equals(unselectedItemColor));
expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size));
// There should not be any [Opacity] or [FadeTransition] widgets
// since showUnselectedLabels and showSelectedLabels are true.
final Finder findOpacity = find.descendant(
of: find.byType(BottomNavigationBar),
matching: find.byType(Opacity),
);
final Finder findFadeTransition = find.descendant(
of: find.byType(BottomNavigationBar),
matching: find.byType(FadeTransition),
);
expect(findOpacity, findsNothing);
expect(findFadeTransition, findsNothing);
expect(_material(tester).elevation, equals(elevation));
expect(_material(tester).color, equals(backgroundColor));
});
testWidgets('BottomNavigationBar properties are taken over the theme values', (WidgetTester tester) async {
const Color themeBackgroundColor = Color(0xFF000001);
const Color themeSelectedItemColor = Color(0xFF000002);
const Color themeUnselectedItemColor = Color(0xFF000003);
const IconThemeData themeSelectedIconTheme = IconThemeData(size: 10);
const IconThemeData themeUnselectedIconTheme = IconThemeData(size: 11);
const TextStyle themeSelectedTextStyle = TextStyle(fontSize: 22);
const TextStyle themeUnselectedTextStyle = TextStyle(fontSize: 21);
const double themeElevation = 9.0;
const Color backgroundColor = Color(0xFF000004);
const Color selectedItemColor = Color(0xFF000005);
const Color unselectedItemColor = Color(0xFF000006);
const IconThemeData selectedIconTheme = IconThemeData(size: 15);
const IconThemeData unselectedIconTheme = IconThemeData(size: 16);
const TextStyle selectedTextStyle = TextStyle(fontSize: 25);
const TextStyle unselectedTextStyle = TextStyle(fontSize: 26);
const double elevation = 7.0;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: themeBackgroundColor,
selectedItemColor: themeSelectedItemColor,
unselectedItemColor: themeUnselectedItemColor,
selectedIconTheme: themeSelectedIconTheme,
unselectedIconTheme: themeUnselectedIconTheme,
elevation: themeElevation,
showUnselectedLabels: false,
showSelectedLabels: false,
type: BottomNavigationBarType.shifting,
selectedLabelStyle: themeSelectedTextStyle,
unselectedLabelStyle: themeUnselectedTextStyle,
),
),
home: Scaffold(
bottomNavigationBar: BottomNavigationBar(
backgroundColor: backgroundColor,
selectedItemColor: selectedItemColor,
unselectedItemColor: unselectedItemColor,
selectedIconTheme: selectedIconTheme,
unselectedIconTheme: unselectedIconTheme,
elevation: elevation,
showUnselectedLabels: true,
showSelectedLabels: true,
type: BottomNavigationBarType.fixed,
selectedLabelStyle: selectedTextStyle,
unselectedLabelStyle: unselectedTextStyle,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.ac_unit),
title: Text('AC'),
),
BottomNavigationBarItem(
icon: Icon(Icons.access_alarm),
title: Text('Alarm'),
),
],
),
),
),
);
final TextStyle selectedFontStyle = tester.renderObject<RenderParagraph>(find.text('AC')).text.style;
final TextStyle selectedIcon = _iconStyle(tester, Icons.ac_unit);
final TextStyle unselectedIcon = _iconStyle(tester, Icons.access_alarm);
expect(selectedFontStyle.fontSize, selectedFontStyle.fontSize);
// Unselected label has a font size of 22 but is scaled down to be font size 21.
expect(
tester.firstWidget<Transform>(find.ancestor(of: find.text('Alarm'), matching: find.byType(Transform))).transform,
equals(Matrix4.diagonal3(Vector3.all(unselectedTextStyle.fontSize / selectedTextStyle.fontSize))),
);
expect(selectedIcon.color, equals(selectedItemColor));
expect(selectedIcon.fontSize, equals(selectedIconTheme.size));
expect(unselectedIcon.color, equals(unselectedItemColor));
expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size));
// There should not be any [Opacity] or [FadeTransition] widgets
// since showUnselectedLabels and showSelectedLabels are true.
final Finder findOpacity = find.descendant(
of: find.byType(BottomNavigationBar),
matching: find.byType(Opacity),
);
final Finder findFadeTransition = find.descendant(
of: find.byType(BottomNavigationBar),
matching: find.byType(FadeTransition),
);
expect(findOpacity, findsNothing);
expect(findFadeTransition, findsNothing);
expect(_material(tester).elevation, equals(elevation));
expect(_material(tester).color, equals(backgroundColor));
});
}
TextStyle _iconStyle(WidgetTester tester, IconData icon) {
final RichText iconRichText = tester.widget<RichText>(
find.descendant(of: find.byIcon(icon), matching: find.byType(RichText)),
);
return iconRichText.text.style;
}
Material _material(WidgetTester tester) {
return tester.firstWidget<Material>(
find.descendant(of: find.byType(BottomNavigationBar), matching: find.byType(Material)),
);
}
...@@ -280,6 +280,7 @@ void main() { ...@@ -280,6 +280,7 @@ void main() {
bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.black), bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.black),
dividerTheme: const DividerThemeData(color: Colors.black), dividerTheme: const DividerThemeData(color: Colors.black),
buttonBarTheme: const ButtonBarThemeData(alignment: MainAxisAlignment.start), buttonBarTheme: const ButtonBarThemeData(alignment: MainAxisAlignment.start),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed),
); );
final SliderThemeData otherSliderTheme = SliderThemeData.fromPrimaryColors( final SliderThemeData otherSliderTheme = SliderThemeData.fromPrimaryColors(
...@@ -360,6 +361,7 @@ void main() { ...@@ -360,6 +361,7 @@ void main() {
bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.white), bannerTheme: const MaterialBannerThemeData(backgroundColor: Colors.white),
dividerTheme: const DividerThemeData(color: Colors.white), dividerTheme: const DividerThemeData(color: Colors.white),
buttonBarTheme: const ButtonBarThemeData(alignment: MainAxisAlignment.end), buttonBarTheme: const ButtonBarThemeData(alignment: MainAxisAlignment.end),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(type: BottomNavigationBarType.shifting),
); );
final ThemeData themeDataCopy = theme.copyWith( final ThemeData themeDataCopy = theme.copyWith(
...@@ -426,6 +428,7 @@ void main() { ...@@ -426,6 +428,7 @@ void main() {
bannerTheme: otherTheme.bannerTheme, bannerTheme: otherTheme.bannerTheme,
dividerTheme: otherTheme.dividerTheme, dividerTheme: otherTheme.dividerTheme,
buttonBarTheme: otherTheme.buttonBarTheme, buttonBarTheme: otherTheme.buttonBarTheme,
bottomNavigationBarTheme: otherTheme.bottomNavigationBarTheme,
); );
expect(themeDataCopy.brightness, equals(otherTheme.brightness)); expect(themeDataCopy.brightness, equals(otherTheme.brightness));
...@@ -493,6 +496,7 @@ void main() { ...@@ -493,6 +496,7 @@ void main() {
expect(themeDataCopy.bannerTheme, equals(otherTheme.bannerTheme)); expect(themeDataCopy.bannerTheme, equals(otherTheme.bannerTheme));
expect(themeDataCopy.dividerTheme, equals(otherTheme.dividerTheme)); expect(themeDataCopy.dividerTheme, equals(otherTheme.dividerTheme));
expect(themeDataCopy.buttonBarTheme, equals(otherTheme.buttonBarTheme)); expect(themeDataCopy.buttonBarTheme, equals(otherTheme.buttonBarTheme));
expect(themeDataCopy.bottomNavigationBarTheme, equals(otherTheme.bottomNavigationBarTheme));
}); });
testWidgets('ThemeData.toString has less than 200 characters output', (WidgetTester tester) async { testWidgets('ThemeData.toString has less than 200 characters output', (WidgetTester tester) async {
......
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