// 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 'navigation_rail.dart'; import 'theme.dart'; /// Defines default property values for descendant [NavigationRail] /// widgets. /// /// Descendant widgets obtain the current [NavigationRailThemeData] object /// using `NavigationRailTheme.of(context)`. Instances of /// [NavigationRailThemeData] can be customized with /// [NavigationRailThemeData.copyWith]. /// /// Typically a [NavigationRailThemeData] is specified as part of the /// overall [Theme] with [ThemeData.navigationRailTheme]. /// /// All [NavigationRailThemeData] properties are `null` by default. /// When null, the [NavigationRail] will use the values from [ThemeData] /// if they exist, otherwise it will provide its own defaults based on the /// overall [Theme]'s textTheme and colorScheme. See the individual /// [NavigationRail] properties for details. /// /// See also: /// /// * [ThemeData], which describes the overall theme information for the /// application. @immutable class NavigationRailThemeData with Diagnosticable { /// Creates a theme that can be used for [ThemeData.navigationRailTheme]. const NavigationRailThemeData({ this.backgroundColor, this.elevation, this.unselectedLabelTextStyle, this.selectedLabelTextStyle, this.unselectedIconTheme, this.selectedIconTheme, this.groupAlignment, this.labelType, }); /// Color to be used for the [NavigationRail]'s background. final Color? backgroundColor; /// The z-coordinate to be used for the [NavigationRail]'s elevation. final double? elevation; /// The style to merge with the default text style for /// [NavigationRailDestination] labels, when the destination is not selected. final TextStyle? unselectedLabelTextStyle; /// The style to merge with the default text style for /// [NavigationRailDestination] labels, when the destination is selected. final TextStyle? selectedLabelTextStyle; /// The theme to merge with the default icon theme for /// [NavigationRailDestination] icons, when the destination is not selected. final IconThemeData? unselectedIconTheme; /// The theme to merge with the default icon theme for /// [NavigationRailDestination] icons, when the destination is selected. final IconThemeData? selectedIconTheme; /// The alignment for the [NavigationRailDestination]s as they are positioned /// within the [NavigationRail]. final double? groupAlignment; /// The type that defines the layout and behavior of the labels in the /// [NavigationRail]. final NavigationRailLabelType? labelType; /// Creates a copy of this object with the given fields replaced with the /// new values. NavigationRailThemeData copyWith({ Color? backgroundColor, double? elevation, TextStyle? unselectedLabelTextStyle, TextStyle? selectedLabelTextStyle, IconThemeData? unselectedIconTheme, IconThemeData? selectedIconTheme, double? groupAlignment, NavigationRailLabelType? labelType, }) { return NavigationRailThemeData( backgroundColor: backgroundColor ?? this.backgroundColor, elevation: elevation ?? this.elevation, unselectedLabelTextStyle: unselectedLabelTextStyle ?? this.unselectedLabelTextStyle, selectedLabelTextStyle: selectedLabelTextStyle ?? this.selectedLabelTextStyle, unselectedIconTheme: unselectedIconTheme ?? this.unselectedIconTheme, selectedIconTheme: selectedIconTheme ?? this.selectedIconTheme, groupAlignment: groupAlignment ?? this.groupAlignment, labelType: labelType ?? this.labelType, ); } /// Linearly interpolate between two navigation rail themes. /// /// If both arguments are null then null is returned. /// /// {@macro dart.ui.shadow.lerp} static NavigationRailThemeData? lerp(NavigationRailThemeData? a, NavigationRailThemeData? b, double t) { assert(t != null); if (a == null && b == null) return null; return NavigationRailThemeData( backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), unselectedLabelTextStyle: TextStyle.lerp(a?.unselectedLabelTextStyle, b?.unselectedLabelTextStyle, t), selectedLabelTextStyle: TextStyle.lerp(a?.selectedLabelTextStyle, b?.selectedLabelTextStyle, t), unselectedIconTheme: IconThemeData.lerp(a?.unselectedIconTheme, b?.unselectedIconTheme, t), selectedIconTheme: IconThemeData.lerp(a?.selectedIconTheme, b?.selectedIconTheme, t), groupAlignment: lerpDouble(a?.groupAlignment, b?.groupAlignment, t), labelType: t < 0.5 ? a?.labelType : b?.labelType, ); } @override int get hashCode { return hashValues( backgroundColor, elevation, unselectedLabelTextStyle, selectedLabelTextStyle, unselectedIconTheme, selectedIconTheme, groupAlignment, labelType, ); } @override bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; return other is NavigationRailThemeData && other.backgroundColor == backgroundColor && other.elevation == elevation && other.unselectedLabelTextStyle == unselectedLabelTextStyle && other.selectedLabelTextStyle == selectedLabelTextStyle && other.unselectedIconTheme == unselectedIconTheme && other.selectedIconTheme == selectedIconTheme && other.groupAlignment == groupAlignment && other.labelType == labelType; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); const NavigationRailThemeData defaultData = NavigationRailThemeData(); properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: defaultData.backgroundColor)); properties.add(DoubleProperty('elevation', elevation, defaultValue: defaultData.elevation)); properties.add(DiagnosticsProperty<TextStyle>('unselectedLabelTextStyle', unselectedLabelTextStyle, defaultValue: defaultData.unselectedLabelTextStyle)); properties.add(DiagnosticsProperty<TextStyle>('selectedLabelTextStyle', selectedLabelTextStyle, defaultValue: defaultData.selectedLabelTextStyle)); properties.add(DiagnosticsProperty<IconThemeData>('unselectedIconTheme', unselectedIconTheme, defaultValue: defaultData.unselectedIconTheme)); properties.add(DiagnosticsProperty<IconThemeData>('selectedIconTheme', selectedIconTheme, defaultValue: defaultData.selectedIconTheme)); properties.add(DoubleProperty('groupAlignment', groupAlignment, defaultValue: defaultData.groupAlignment)); properties.add(DiagnosticsProperty<NavigationRailLabelType>('labelType', labelType, defaultValue: defaultData.labelType)); } } /// An inherited widget that defines visual properties for [NavigationRail]s and /// [NavigationRailDestination]s in this widget's subtree. /// /// Values specified here are used for [NavigationRail] properties that are not /// given an explicit non-null value. class NavigationRailTheme extends InheritedTheme { /// Creates a navigation rail theme that controls the /// [NavigationRailThemeData] properties for a [NavigationRail]. /// /// The data argument must not be null. const NavigationRailTheme({ Key? key, required this.data, required Widget child, }) : assert(data != null), super(key: key, child: child); /// Specifies the background color, elevation, label text style, icon theme, /// group alignment, and label type and border values for descendant /// [NavigationRail] widgets. final NavigationRailThemeData data; /// The closest instance of this class that encloses the given context. /// /// If there is no enclosing [NavigationRailTheme] widget, then /// [ThemeData.navigationRailTheme] is used. /// /// Typical usage is as follows: /// /// ```dart /// NavigationRailTheme theme = NavigationRailTheme.of(context); /// ``` static NavigationRailThemeData of(BuildContext context) { final NavigationRailTheme? navigationRailTheme = context.dependOnInheritedWidgetOfExactType<NavigationRailTheme>(); return navigationRailTheme?.data ?? Theme.of(context).navigationRailTheme; } @override Widget wrap(BuildContext context, Widget child) { return NavigationRailTheme(data: data, child: child); } @override bool updateShouldNotify(NavigationRailTheme oldWidget) => data != oldWidget.data; }