// 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/rendering.dart'; import 'package:flutter/widgets.dart'; import 'material_state.dart'; import 'navigation_bar.dart'; import 'theme.dart'; // Examples can assume: // late BuildContext context; /// Defines default property values for descendant [NavigationBar] /// widgets. /// /// Descendant widgets obtain the current [NavigationBarThemeData] object /// using `NavigationBarTheme.of(context)`. Instances of /// [NavigationBarThemeData] can be customized with /// [NavigationBarThemeData.copyWith]. /// /// Typically a [NavigationBarThemeData] is specified as part of the /// overall [Theme] with [ThemeData.navigationBarTheme]. Alternatively, a /// [NavigationBarTheme] inherited widget can be used to theme [NavigationBar]s /// in a subtree of widgets. /// /// All [NavigationBarThemeData] properties are `null` by default. /// When null, the [NavigationBar] will provide its own defaults based on the /// overall [Theme]'s textTheme and colorScheme. See the individual /// [NavigationBar] properties for details. /// /// See also: /// /// * [ThemeData], which describes the overall theme information for the /// application. @immutable class NavigationBarThemeData with Diagnosticable { /// Creates a theme that can be used for [ThemeData.navigationBarTheme] and /// [NavigationBarTheme]. const NavigationBarThemeData({ this.height, this.backgroundColor, this.elevation, this.shadowColor, this.surfaceTintColor, this.indicatorColor, this.indicatorShape, this.labelTextStyle, this.iconTheme, this.labelBehavior, }); /// Overrides the default value of [NavigationBar.height]. final double? height; /// Overrides the default value of [NavigationBar.backgroundColor]. final Color? backgroundColor; /// Overrides the default value of [NavigationBar.elevation]. final double? elevation; /// Overrides the default value of [NavigationBar.shadowColor]. final Color? shadowColor; /// Overrides the default value of [NavigationBar.surfaceTintColor]. final Color? surfaceTintColor; /// Overrides the default value of [NavigationBar]'s selection indicator. final Color? indicatorColor; /// Overrides the default shape of the [NavigationBar]'s selection indicator. final ShapeBorder? indicatorShape; /// The style to merge with the default text style for /// [NavigationDestination] labels. /// /// You can use this to specify a different style when the label is selected. final MaterialStateProperty<TextStyle?>? labelTextStyle; /// The theme to merge with the default icon theme for /// [NavigationDestination] icons. /// /// You can use this to specify a different icon theme when the icon is /// selected. final MaterialStateProperty<IconThemeData?>? iconTheme; /// Overrides the default value of [NavigationBar.labelBehavior]. final NavigationDestinationLabelBehavior? labelBehavior; /// Creates a copy of this object with the given fields replaced with the /// new values. NavigationBarThemeData copyWith({ double? height, Color? backgroundColor, double? elevation, Color? shadowColor, Color? surfaceTintColor, Color? indicatorColor, ShapeBorder? indicatorShape, MaterialStateProperty<TextStyle?>? labelTextStyle, MaterialStateProperty<IconThemeData?>? iconTheme, NavigationDestinationLabelBehavior? labelBehavior, }) { return NavigationBarThemeData( height: height ?? this.height, backgroundColor: backgroundColor ?? this.backgroundColor, elevation: elevation ?? this.elevation, shadowColor: shadowColor ?? this.shadowColor, surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, indicatorColor: indicatorColor ?? this.indicatorColor, indicatorShape: indicatorShape ?? this.indicatorShape, labelTextStyle: labelTextStyle ?? this.labelTextStyle, iconTheme: iconTheme ?? this.iconTheme, labelBehavior: labelBehavior ?? this.labelBehavior, ); } /// Linearly interpolate between two navigation rail themes. /// /// If both arguments are null then null is returned. /// /// {@macro dart.ui.shadow.lerp} static NavigationBarThemeData? lerp(NavigationBarThemeData? a, NavigationBarThemeData? b, double t) { if (identical(a, b)) { return a; } return NavigationBarThemeData( height: lerpDouble(a?.height, b?.height, t), backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), indicatorColor: Color.lerp(a?.indicatorColor, b?.indicatorColor, t), indicatorShape: ShapeBorder.lerp(a?.indicatorShape, b?.indicatorShape, t), labelTextStyle: MaterialStateProperty.lerp<TextStyle?>(a?.labelTextStyle, b?.labelTextStyle, t, TextStyle.lerp), iconTheme: MaterialStateProperty.lerp<IconThemeData?>(a?.iconTheme, b?.iconTheme, t, IconThemeData.lerp), labelBehavior: t < 0.5 ? a?.labelBehavior : b?.labelBehavior, ); } @override int get hashCode => Object.hash( height, backgroundColor, elevation, shadowColor, surfaceTintColor, indicatorColor, indicatorShape, labelTextStyle, iconTheme, labelBehavior, ); @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other.runtimeType != runtimeType) { return false; } return other is NavigationBarThemeData && other.height == height && other.backgroundColor == backgroundColor && other.elevation == elevation && other.shadowColor == shadowColor && other.surfaceTintColor == surfaceTintColor && other.indicatorColor == indicatorColor && other.indicatorShape == indicatorShape && other.labelTextStyle == labelTextStyle && other.iconTheme == iconTheme && other.labelBehavior == labelBehavior; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DoubleProperty('height', height, defaultValue: null)); properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(ColorProperty('indicatorColor', indicatorColor, defaultValue: null)); properties.add(DiagnosticsProperty<ShapeBorder>('indicatorShape', indicatorShape, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<TextStyle?>>('labelTextStyle', labelTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<IconThemeData?>>('iconTheme', iconTheme, defaultValue: null)); properties.add(DiagnosticsProperty<NavigationDestinationLabelBehavior>('labelBehavior', labelBehavior, defaultValue: null)); } } /// An inherited widget that defines visual properties for [NavigationBar]s and /// [NavigationDestination]s in this widget's subtree. /// /// Values specified here are used for [NavigationBar] properties that are not /// given an explicit non-null value. /// /// See also: /// /// * [ThemeData.navigationBarTheme], which describes the /// [NavigationBarThemeData] in the overall theme for the application. class NavigationBarTheme extends InheritedTheme { /// Creates a navigation rail theme that controls the /// [NavigationBarThemeData] properties for a [NavigationBar]. /// /// The data argument must not be null. const NavigationBarTheme({ super.key, required this.data, required super.child, }); /// Specifies the background color, label text style, icon theme, and label /// type values for descendant [NavigationBar] widgets. final NavigationBarThemeData data; /// The closest instance of this class that encloses the given context. /// /// If there is no enclosing [NavigationBarTheme] widget, then /// [ThemeData.navigationBarTheme] is used. /// /// Typical usage is as follows: /// /// ```dart /// NavigationBarThemeData theme = NavigationBarTheme.of(context); /// ``` static NavigationBarThemeData of(BuildContext context) { final NavigationBarTheme? navigationBarTheme = context.dependOnInheritedWidgetOfExactType<NavigationBarTheme>(); return navigationBarTheme?.data ?? Theme.of(context).navigationBarTheme; } @override Widget wrap(BuildContext context, Widget child) { return NavigationBarTheme(data: data, child: child); } @override bool updateShouldNotify(NavigationBarTheme oldWidget) => data != oldWidget.data; }