snack_bar.dart 5.27 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/widgets.dart';
6

7
import 'button.dart';
8
import 'flat_button.dart';
9
import 'material.dart';
10
import 'theme_data.dart';
11
import 'theme.dart';
12
import 'typography.dart';
Matt Perry's avatar
Matt Perry committed
13

Hixie's avatar
Hixie committed
14
// https://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-specs
15
const double _kSideMargins = 24.0;
Hixie's avatar
Hixie committed
16
const double _kSingleLineVerticalPadding = 14.0;
17 18
const double _kMultiLineVerticalTopPadding = 24.0;
const double _kMultiLineVerticalSpaceBetweenTextAndButtons = 10.0;
19
const Color _kSnackBackground = const Color(0xFF323232);
Matt Perry's avatar
Matt Perry committed
20

Hixie's avatar
Hixie committed
21 22 23 24 25 26
// TODO(ianh): We should check if the given text and actions are going to fit on
// one line or not, and if they are, use the single-line layout, and if not, use
// the multiline layout. See link above.

// TODO(ianh): Implement the Tablet version of snackbar if we're "on a tablet".

27
const Duration _kSnackBarTransitionDuration = const Duration(milliseconds: 250);
Hixie's avatar
Hixie committed
28 29
const Duration kSnackBarShortDisplayDuration = const Duration(milliseconds: 1500);
const Duration kSnackBarMediumDisplayDuration = const Duration(milliseconds: 2750);
30
const Curve _snackBarHeightCurve = Curves.fastOutSlowIn;
31
const Curve _snackBarFadeCurve = const Interval(0.72, 1.0, curve: Curves.fastOutSlowIn);
Hixie's avatar
Hixie committed
32

33 34 35 36 37
/// A button for a [SnackBar], known as an "action".
///
/// Snack bar actions are always enabled. If you want to disable a snack bar
/// action, simply don't include it in the snack bar.
///
38
/// See also: <https://www.google.com/design/spec/components/snackbars-toasts.html>
39
class SnackBarAction extends StatelessWidget {
40
  SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) {
41
    assert(label != null);
42
    assert(onPressed != null);
43 44
  }

45
  /// The button label.
46
  final String label;
47 48

  /// The callback to be invoked when the button is pressed. Must be non-null.
49
  final VoidCallback onPressed;
50

51
  @override
Hixie's avatar
Hixie committed
52
  Widget build(BuildContext context) {
53
    return new Container(
54
      margin: const EdgeInsets.only(left: _kSideMargins),
55 56 57
      child: new FlatButton(
        onPressed: onPressed,
        textTheme: ButtonColor.accent,
58 59 60 61 62
        child: new Text(label)
      )
    );
  }
}
63

64 65 66 67 68 69
/// A lightweight message with an optional action which briefly displays at the
/// bottom of the screen.
///
/// Displayed with the Scaffold.of().showSnackBar() API.
///
/// See also:
70
///
71 72
///  * [Scaffold.of] and [ScaffoldState.showSnackBar]
///  * [SnackBarAction]
73
///  * <https://www.google.com/design/spec/components/snackbars-toasts.html>
74
class SnackBar extends StatelessWidget {
Hixie's avatar
Hixie committed
75
  SnackBar({
76 77
    Key key,
    this.content,
78
    this.action,
Hixie's avatar
Hixie committed
79
    this.duration: kSnackBarShortDisplayDuration,
80
    this.animation
81
  }) : super(key: key) {
82 83 84
    assert(content != null);
  }

85
  final Widget content;
86
  final SnackBarAction action;
Hixie's avatar
Hixie committed
87
  final Duration duration;
88
  final Animation<double> animation;
89

90
  @override
91
  Widget build(BuildContext context) {
92
    assert(animation != null);
Hixie's avatar
Hixie committed
93
    List<Widget> children = <Widget>[
94 95
      new Flexible(
        child: new Container(
96
          margin: const EdgeInsets.symmetric(vertical: _kSingleLineVerticalPadding),
97
          child: new DefaultTextStyle(
98
            style: Typography.white.subhead,
99
            child: content
100 101 102
          )
        )
      )
103
    ];
104 105
    if (action != null)
      children.add(action);
106 107
    CurvedAnimation heightAnimation = new CurvedAnimation(parent: animation, curve: _snackBarHeightCurve);
    CurvedAnimation fadeAnimation = new CurvedAnimation(parent: animation, curve: _snackBarFadeCurve);
108
    ThemeData theme = Theme.of(context);
109 110 111
    return new ClipRect(
      child: new AnimatedBuilder(
        animation: heightAnimation,
112
        builder: (BuildContext context, Widget child) {
113
          return new Align(
114
            alignment: FractionalOffset.topLeft,
115 116 117
            heightFactor: heightAnimation.value,
            child: child
          );
118
        },
Hixie's avatar
Hixie committed
119 120 121 122 123 124
        child: new Semantics(
          container: true,
          child: new Material(
            elevation: 6,
            color: _kSnackBackground,
            child: new Container(
125
              margin: const EdgeInsets.symmetric(horizontal: _kSideMargins),
Hixie's avatar
Hixie committed
126 127 128 129 130
              child: new Theme(
                data: new ThemeData(
                  brightness: ThemeBrightness.dark,
                  accentColor: theme.accentColor,
                  accentColorBrightness: theme.accentColorBrightness,
131
                  textTheme: Typography.white
Hixie's avatar
Hixie committed
132 133 134 135 136
                ),
                child: new FadeTransition(
                  opacity: fadeAnimation,
                  child: new Row(
                    children: children,
137
                    crossAxisAlignment: CrossAxisAlignment.center
Hixie's avatar
Hixie committed
138
                  )
139 140 141 142 143
                )
              )
            )
          )
        )
144 145
      )
    );
146
  }
147

Hixie's avatar
Hixie committed
148
  // API for Scaffold.addSnackBar():
149

150 151
  static AnimationController createAnimationController() {
    return new AnimationController(
152
      duration: _kSnackBarTransitionDuration,
Hixie's avatar
Hixie committed
153 154 155
      debugLabel: 'SnackBar'
    );
  }
156

157
  SnackBar withAnimation(Animation<double> newAnimation, { Key fallbackKey }) {
Hixie's avatar
Hixie committed
158
    return new SnackBar(
159
      key: key ?? fallbackKey,
Hixie's avatar
Hixie committed
160
      content: content,
161
      action: action,
Hixie's avatar
Hixie committed
162
      duration: duration,
163
      animation: newAnimation
Hixie's avatar
Hixie committed
164 165
    );
  }
166
}