blob: 494e59ec7740c540c0494d1b4a1a00e743913896 [file] [log] [blame] [edit]
// 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 'material_state.dart';
import 'theme.dart';
// Examples can assume:
// late BuildContext context;
/// 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,
this.enableFeedback,
this.landscapeLayout,
this.mouseCursor,
});
/// 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].
///
/// If [BottomNavigationBar.selectedIconTheme] is non-null on the widget,
/// the whole [IconThemeData] from the widget will be used over this
/// [selectedIconTheme].
///
/// See [BottomNavigationBar.selectedIconTheme].
final IconThemeData? selectedIconTheme;
/// The size, opacity, and color of the icon in the currently unselected
/// [BottomNavigationBarItem.icon]s.
///
/// If [BottomNavigationBar.unselectedIconTheme] is non-null on the widget,
/// the whole [IconThemeData] from the widget will be used over this
/// [unselectedIconTheme].
///
/// 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 selected [BottomNavigationBarItem].
///
/// See [BottomNavigationBar.showSelectedLabels].
final bool? showSelectedLabels;
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
///
/// See [BottomNavigationBar.showUnselectedLabels].
final bool? showUnselectedLabels;
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// See [BottomNavigationBar.type].
final BottomNavigationBarType? type;
/// If specified, defines the feedback property for [BottomNavigationBar].
///
/// If [BottomNavigationBar.enableFeedback] is provided, [enableFeedback] is ignored.
final bool? enableFeedback;
/// If non-null, overrides the [BottomNavigationBar.landscapeLayout] property.
final BottomNavigationBarLandscapeLayout? landscapeLayout;
/// If specified, overrides the default value of [BottomNavigationBar.mouseCursor].
final MaterialStateProperty<MouseCursor?>? mouseCursor;
/// 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,
bool? enableFeedback,
BottomNavigationBarLandscapeLayout? landscapeLayout,
MaterialStateProperty<MouseCursor?>? mouseCursor,
}) {
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,
enableFeedback: enableFeedback ?? this.enableFeedback,
landscapeLayout: landscapeLayout ?? this.landscapeLayout,
mouseCursor: mouseCursor ?? this.mouseCursor,
);
}
/// 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) {
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,
enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
landscapeLayout: t < 0.5 ? a?.landscapeLayout : b?.landscapeLayout,
mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
);
}
@override
int get hashCode => Object.hash(
backgroundColor,
elevation,
selectedIconTheme,
unselectedIconTheme,
selectedItemColor,
unselectedItemColor,
selectedLabelStyle,
unselectedLabelStyle,
showSelectedLabels,
showUnselectedLabels,
type,
enableFeedback,
landscapeLayout,
mouseCursor,
);
@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
&& other.enableFeedback == enableFeedback
&& other.landscapeLayout == landscapeLayout
&& other.mouseCursor == mouseCursor;
}
@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));
properties.add(DiagnosticsProperty<bool>('enableFeedback', enableFeedback, defaultValue: null));
properties.add(DiagnosticsProperty<BottomNavigationBarLandscapeLayout>('landscapeLayout', landscapeLayout, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, 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({
super.key,
required this.data,
required super.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;
}