snack_bar_theme.dart 11.6 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9
// 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';

10
import 'material_state.dart';
11 12 13 14
import 'theme.dart';

/// Defines where a [SnackBar] should appear within a [Scaffold] and how its
/// location should be adjusted when the scaffold also includes a
15
/// [FloatingActionButton] or a [BottomNavigationBar].
16 17 18 19
enum SnackBarBehavior {
  /// Fixes the [SnackBar] at the bottom of the [Scaffold].
  ///
  /// The exception is that the [SnackBar] will be shown above a
20 21 22
  /// [BottomNavigationBar] or a [NavigationBar]. Additionally, the [SnackBar]
  /// will cause other non-fixed widgets inside [Scaffold] to be pushed above
  /// (for example, the [FloatingActionButton]).
23 24 25
  fixed,

  /// This behavior will cause [SnackBar] to be shown above other widgets in the
26 27 28 29 30
  /// [Scaffold]. This includes being displayed above a [BottomNavigationBar] or
  /// a [NavigationBar], and a [FloatingActionButton] when its location is on the
  /// bottom. When the floating action button location is on the top, this behavior
  /// will cause the [SnackBar] to be shown above other widgets in the [Scaffold]
  /// except the floating action button.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
  ///
  /// See <https://material.io/design/components/snackbars.html> for more details.
  floating,
}

/// Customizes default property values for [SnackBar] widgets.
///
/// Descendant widgets obtain the current [SnackBarThemeData] object using
/// `Theme.of(context).snackBarTheme`. Instances of [SnackBarThemeData] can be
/// customized with [SnackBarThemeData.copyWith].
///
/// Typically a [SnackBarThemeData] is specified as part of the overall [Theme]
/// with [ThemeData.snackBarTheme]. The default for [ThemeData.snackBarTheme]
/// provides all `null` properties.
///
/// All [SnackBarThemeData] properties are `null` by default. When null, the
/// [SnackBar] will provide its own defaults.
///
/// See also:
///
///  * [ThemeData], which describes the overall theme information for the
///    application.
53
@immutable
54
class SnackBarThemeData with Diagnosticable {
55 56 57 58 59 60 61 62

  /// Creates a theme that can be used for [ThemeData.snackBarTheme].
  ///
  /// The [elevation] must be null or non-negative.
  const SnackBarThemeData({
    this.backgroundColor,
    this.actionTextColor,
    this.disabledActionTextColor,
63
    this.contentTextStyle,
64 65 66
    this.elevation,
    this.shape,
    this.behavior,
67
    this.width,
68 69 70
    this.insetPadding,
    this.showCloseIcon,
    this.closeIconColor,
71
    this.actionOverflowThreshold,
72 73
    this.actionBackgroundColor,
    this.disabledActionBackgroundColor
74
  })  : assert(elevation == null || elevation >= 0.0),
75 76 77
        assert(width == null || identical(behavior, SnackBarBehavior.floating),
          'Width can only be set if behaviour is SnackBarBehavior.floating'),
        assert(actionOverflowThreshold == null || (actionOverflowThreshold >= 0 && actionOverflowThreshold <= 1),
78 79 80 81
          'Action overflow threshold must be between 0 and 1 inclusive'),
        assert(actionBackgroundColor is! MaterialStateColor || disabledActionBackgroundColor == null,
          'disabledBackgroundColor must not be provided when background color is '
          'a MaterialStateColor');
82

hangyu's avatar
hangyu committed
83
  /// Overrides the default value for [SnackBar.backgroundColor].
84 85
  ///
  /// If null, [SnackBar] defaults to dark grey: `Color(0xFF323232)`.
86
  final Color? backgroundColor;
87

hangyu's avatar
hangyu committed
88
  /// Overrides the default value for [SnackBarAction.textColor].
89
  ///
90 91
  /// If null, [SnackBarAction] defaults to [ColorScheme.secondary] of
  /// [ThemeData.colorScheme] .
92
  final Color? actionTextColor;
93

hangyu's avatar
hangyu committed
94
  /// Overrides the default value for [SnackBarAction.disabledTextColor].
95 96 97 98
  ///
  /// If null, [SnackBarAction] defaults to [ColorScheme.onSurface] with its
  /// opacity set to 0.30 if the [Theme]'s brightness is [Brightness.dark], 0.38
  /// otherwise.
99
  final Color? disabledActionTextColor;
100

101 102 103
  /// Used to configure the [DefaultTextStyle] for the [SnackBar.content] widget.
  ///
  /// If null, [SnackBar] defines its default.
104
  final TextStyle? contentTextStyle;
105

hangyu's avatar
hangyu committed
106
  /// Overrides the default value for [SnackBar.elevation].
107 108
  ///
  /// If null, [SnackBar] uses a default of 6.0.
109
  final double? elevation;
110

hangyu's avatar
hangyu committed
111
  /// Overrides the default value for [SnackBar.shape].
112 113 114 115 116 117
  ///
  /// If null, [SnackBar] provides different defaults depending on the
  /// [SnackBarBehavior]. For [SnackBarBehavior.fixed], no overriding shape is
  /// specified, so the [SnackBar] is rectangular. For
  /// [SnackBarBehavior.floating], it uses a [RoundedRectangleBorder] with a
  /// circular corner radius of 4.0.
118
  final ShapeBorder? shape;
119

hangyu's avatar
hangyu committed
120
  /// Overrides the default value for [SnackBar.behavior].
121 122
  ///
  /// If null, [SnackBar] will default to [SnackBarBehavior.fixed].
123
  final SnackBarBehavior? behavior;
124

hangyu's avatar
hangyu committed
125
  /// Overrides the default value for [SnackBar.width].
126 127 128 129 130 131
  ///
  /// If this property is null, then the snack bar will take up the full device
  /// width less the margin. This value is only used when [behavior] is
  /// [SnackBarBehavior.floating].
  final double? width;

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
  /// Overrides the default value for [SnackBar.margin].
  ///
  /// This value is only used when [behavior] is [SnackBarBehavior.floating].
  final EdgeInsets? insetPadding;

  /// Overrides the default value for [SnackBar.showCloseIcon].
  ///
  /// Whether to show an optional "Close" icon.
  final bool? showCloseIcon;

  /// Overrides the default value for [SnackBar.closeIconColor].
  ///
  /// This value is only used if [showCloseIcon] is true.
  final Color? closeIconColor;

147 148 149 150
  /// Overrides the default value for [SnackBar.actionOverflowThreshold].
  ///
  /// Must be a value between 0 and 1, if present.
  final double? actionOverflowThreshold;
151 152 153 154 155 156 157 158 159
  /// Overrides default value for [SnackBarAction.backgroundColor].
  ///
  /// If null, [SnackBarAction] falls back to [Colors.transparent].
  final Color? actionBackgroundColor;

  /// Overrides default value for [SnackBarAction.].
  ///
  /// If null, [SnackBarAction] falls back to [Colors.transparent].
  final Color? disabledActionBackgroundColor;
160

161 162 163
  /// Creates a copy of this object with the given fields replaced with the
  /// new values.
  SnackBarThemeData copyWith({
164 165 166 167 168 169 170
    Color? backgroundColor,
    Color? actionTextColor,
    Color? disabledActionTextColor,
    TextStyle? contentTextStyle,
    double? elevation,
    ShapeBorder? shape,
    SnackBarBehavior? behavior,
171
    double? width,
172 173 174
    EdgeInsets? insetPadding,
    bool? showCloseIcon,
    Color? closeIconColor,
175
    double? actionOverflowThreshold,
176 177
    Color? actionBackgroundColor,
    Color? disabledActionBackgroundColor,
178 179 180 181 182
  }) {
    return SnackBarThemeData(
      backgroundColor: backgroundColor ?? this.backgroundColor,
      actionTextColor: actionTextColor ?? this.actionTextColor,
      disabledActionTextColor: disabledActionTextColor ?? this.disabledActionTextColor,
183
      contentTextStyle: contentTextStyle ?? this.contentTextStyle,
184 185 186
      elevation: elevation ?? this.elevation,
      shape: shape ?? this.shape,
      behavior: behavior ?? this.behavior,
187
      width: width ?? this.width,
188 189 190
      insetPadding: insetPadding ?? this.insetPadding,
      showCloseIcon: showCloseIcon ?? this.showCloseIcon,
      closeIconColor: closeIconColor ?? this.closeIconColor,
191
      actionOverflowThreshold: actionOverflowThreshold ?? this.actionOverflowThreshold,
192 193
      actionBackgroundColor: actionBackgroundColor ?? this.actionBackgroundColor,
      disabledActionBackgroundColor: disabledActionBackgroundColor ?? this.disabledActionBackgroundColor,
194 195 196 197 198 199 200 201
    );
  }

  /// Linearly interpolate between two SnackBar Themes.
  ///
  /// The argument `t` must not be null.
  ///
  /// {@macro dart.ui.shadow.lerp}
202
  static SnackBarThemeData lerp(SnackBarThemeData? a, SnackBarThemeData? b, double t) {
203 204 205
    if (identical(a, b) && a != null) {
      return a;
    }
206 207 208 209
    return SnackBarThemeData(
      backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
      actionTextColor: Color.lerp(a?.actionTextColor, b?.actionTextColor, t),
      disabledActionTextColor: Color.lerp(a?.disabledActionTextColor, b?.disabledActionTextColor, t),
210
      contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
211 212
      elevation: lerpDouble(a?.elevation, b?.elevation, t),
      shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
213
      behavior: t < 0.5 ? a?.behavior : b?.behavior,
214
      width: lerpDouble(a?.width, b?.width, t),
215 216
      insetPadding: EdgeInsets.lerp(a?.insetPadding, b?.insetPadding, t),
      closeIconColor: Color.lerp(a?.closeIconColor, b?.closeIconColor, t),
217
      actionOverflowThreshold: lerpDouble(a?.actionOverflowThreshold, b?.actionOverflowThreshold, t),
218 219
      actionBackgroundColor: Color.lerp(a?.actionBackgroundColor, b?.actionBackgroundColor, t),
      disabledActionBackgroundColor: Color.lerp(a?.disabledActionBackgroundColor, b?.disabledActionBackgroundColor, t),
220 221 222 223
    );
  }

  @override
224
  int get hashCode => Object.hash(
225 226 227 228 229 230 231 232
        backgroundColor,
        actionTextColor,
        disabledActionTextColor,
        contentTextStyle,
        elevation,
        shape,
        behavior,
        width,
233 234 235
        insetPadding,
        showCloseIcon,
        closeIconColor,
236
        actionOverflowThreshold,
237 238
        actionBackgroundColor,
        disabledActionBackgroundColor
239
      );
240 241

  @override
242
  bool operator ==(Object other) {
243
    if (identical(this, other)) {
244
      return true;
245 246
    }
    if (other.runtimeType != runtimeType) {
247
      return false;
248
    }
249 250 251 252 253 254 255
    return other is SnackBarThemeData
        && other.backgroundColor == backgroundColor
        && other.actionTextColor == actionTextColor
        && other.disabledActionTextColor == disabledActionTextColor
        && other.contentTextStyle == contentTextStyle
        && other.elevation == elevation
        && other.shape == shape
256
        && other.behavior == behavior
257 258 259
        && other.width == width
        && other.insetPadding == insetPadding
        && other.showCloseIcon == showCloseIcon
260
        && other.closeIconColor == closeIconColor
261 262 263
        && other.actionOverflowThreshold == actionOverflowThreshold
        && other.actionBackgroundColor == actionBackgroundColor
        && other.disabledActionBackgroundColor == disabledActionBackgroundColor;
264 265 266 267 268
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
269 270 271
    properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
    properties.add(ColorProperty('actionTextColor', actionTextColor, defaultValue: null));
    properties.add(ColorProperty('disabledActionTextColor', disabledActionTextColor, defaultValue: null));
272
    properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null));
273
    properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
274 275
    properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
    properties.add(DiagnosticsProperty<SnackBarBehavior>('behavior', behavior, defaultValue: null));
276
    properties.add(DoubleProperty('width', width, defaultValue: null));
277 278 279
    properties.add(DiagnosticsProperty<EdgeInsets>('insetPadding', insetPadding, defaultValue: null));
    properties.add(DiagnosticsProperty<bool>('showCloseIcon', showCloseIcon, defaultValue: null));
    properties.add(ColorProperty('closeIconColor', closeIconColor, defaultValue: null));
280
    properties.add(DoubleProperty('actionOverflowThreshold', actionOverflowThreshold, defaultValue: null));
281 282
    properties.add(ColorProperty('actionBackgroundColor', actionBackgroundColor, defaultValue: null));
    properties.add(ColorProperty('disabledActionBackgroundColor', disabledActionBackgroundColor, defaultValue: null));
283 284
  }
}