snack_bar_theme.dart 9.01 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 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
// 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 'theme.dart';

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

  /// This behavior will cause [SnackBar] to be shown above other widgets in the
  /// [Scaffold]. This includes being displayed above a [BottomNavigationBar]
  /// and a [FloatingActionButton].
  ///
  /// 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.
49
@immutable
50
class SnackBarThemeData with Diagnosticable {
51 52 53 54 55 56 57 58

  /// 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,
59
    this.contentTextStyle,
60 61 62
    this.elevation,
    this.shape,
    this.behavior,
63
    this.width,
64 65 66
    this.insetPadding,
    this.showCloseIcon,
    this.closeIconColor,
67 68 69 70 71
  })  : assert(elevation == null || elevation >= 0.0),
        assert(
            width == null ||
                (width != null && identical(behavior, SnackBarBehavior.floating)),
            'Width can only be set if behaviour is SnackBarBehavior.floating');
hangyu's avatar
hangyu committed
72
  /// Overrides the default value for [SnackBar.backgroundColor].
73 74
  ///
  /// If null, [SnackBar] defaults to dark grey: `Color(0xFF323232)`.
75
  final Color? backgroundColor;
76

hangyu's avatar
hangyu committed
77
  /// Overrides the default value for [SnackBarAction.textColor].
78
  ///
79 80
  /// If null, [SnackBarAction] defaults to [ColorScheme.secondary] of
  /// [ThemeData.colorScheme] .
81
  final Color? actionTextColor;
82

hangyu's avatar
hangyu committed
83
  /// Overrides the default value for [SnackBarAction.disabledTextColor].
84 85 86 87
  ///
  /// 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.
88
  final Color? disabledActionTextColor;
89

90 91 92
  /// Used to configure the [DefaultTextStyle] for the [SnackBar.content] widget.
  ///
  /// If null, [SnackBar] defines its default.
93
  final TextStyle? contentTextStyle;
94

hangyu's avatar
hangyu committed
95
  /// Overrides the default value for [SnackBar.elevation].
96 97
  ///
  /// If null, [SnackBar] uses a default of 6.0.
98
  final double? elevation;
99

hangyu's avatar
hangyu committed
100
  /// Overrides the default value for [SnackBar.shape].
101 102 103 104 105 106
  ///
  /// 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.
107
  final ShapeBorder? shape;
108

hangyu's avatar
hangyu committed
109
  /// Overrides the default value for [SnackBar.behavior].
110 111
  ///
  /// If null, [SnackBar] will default to [SnackBarBehavior.fixed].
112
  final SnackBarBehavior? behavior;
113

hangyu's avatar
hangyu committed
114
  /// Overrides the default value for [SnackBar.width].
115 116 117 118 119 120
  ///
  /// 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;

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
  /// 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;

136 137 138
  /// Creates a copy of this object with the given fields replaced with the
  /// new values.
  SnackBarThemeData copyWith({
139 140 141 142 143 144 145
    Color? backgroundColor,
    Color? actionTextColor,
    Color? disabledActionTextColor,
    TextStyle? contentTextStyle,
    double? elevation,
    ShapeBorder? shape,
    SnackBarBehavior? behavior,
146
    double? width,
147 148 149
    EdgeInsets? insetPadding,
    bool? showCloseIcon,
    Color? closeIconColor,
150 151 152 153 154
  }) {
    return SnackBarThemeData(
      backgroundColor: backgroundColor ?? this.backgroundColor,
      actionTextColor: actionTextColor ?? this.actionTextColor,
      disabledActionTextColor: disabledActionTextColor ?? this.disabledActionTextColor,
155
      contentTextStyle: contentTextStyle ?? this.contentTextStyle,
156 157 158
      elevation: elevation ?? this.elevation,
      shape: shape ?? this.shape,
      behavior: behavior ?? this.behavior,
159
      width: width ?? this.width,
160 161 162
      insetPadding: insetPadding ?? this.insetPadding,
      showCloseIcon: showCloseIcon ?? this.showCloseIcon,
      closeIconColor: closeIconColor ?? this.closeIconColor,
163 164 165 166 167 168 169 170
    );
  }

  /// Linearly interpolate between two SnackBar Themes.
  ///
  /// The argument `t` must not be null.
  ///
  /// {@macro dart.ui.shadow.lerp}
171
  static SnackBarThemeData lerp(SnackBarThemeData? a, SnackBarThemeData? b, double t) {
172 173 174 175 176
    assert(t != null);
    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),
177
      contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
178 179
      elevation: lerpDouble(a?.elevation, b?.elevation, t),
      shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
180
      behavior: t < 0.5 ? a?.behavior : b?.behavior,
181
      width: lerpDouble(a?.width, b?.width, t),
182 183
      insetPadding: EdgeInsets.lerp(a?.insetPadding, b?.insetPadding, t),
      closeIconColor: Color.lerp(a?.closeIconColor, b?.closeIconColor, t),
184 185 186 187
    );
  }

  @override
188
  int get hashCode => Object.hash(
189 190 191 192 193 194 195 196
        backgroundColor,
        actionTextColor,
        disabledActionTextColor,
        contentTextStyle,
        elevation,
        shape,
        behavior,
        width,
197 198 199
        insetPadding,
        showCloseIcon,
        closeIconColor,
200
      );
201 202

  @override
203
  bool operator ==(Object other) {
204
    if (identical(this, other)) {
205
      return true;
206 207
    }
    if (other.runtimeType != runtimeType) {
208
      return false;
209
    }
210 211 212 213 214 215 216
    return other is SnackBarThemeData
        && other.backgroundColor == backgroundColor
        && other.actionTextColor == actionTextColor
        && other.disabledActionTextColor == disabledActionTextColor
        && other.contentTextStyle == contentTextStyle
        && other.elevation == elevation
        && other.shape == shape
217
        && other.behavior == behavior
218 219 220 221
        && other.width == width
        && other.insetPadding == insetPadding
        && other.showCloseIcon == showCloseIcon
        && other.closeIconColor == closeIconColor;
222 223 224 225 226
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
227 228 229
    properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
    properties.add(ColorProperty('actionTextColor', actionTextColor, defaultValue: null));
    properties.add(ColorProperty('disabledActionTextColor', disabledActionTextColor, defaultValue: null));
230
    properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null));
231
    properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
232 233
    properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
    properties.add(DiagnosticsProperty<SnackBarBehavior>('behavior', behavior, defaultValue: null));
234
    properties.add(DoubleProperty('width', width, defaultValue: null));
235 236 237
    properties.add(DiagnosticsProperty<EdgeInsets>('insetPadding', insetPadding, defaultValue: null));
    properties.add(DiagnosticsProperty<bool>('showCloseIcon', showCloseIcon, defaultValue: null));
    properties.add(ColorProperty('closeIconColor', closeIconColor, defaultValue: null));
238 239
  }
}