card.dart 6.86 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// 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 'card_theme.dart';
8
import 'colors.dart';
9
import 'material.dart';
Hans Muller's avatar
Hans Muller committed
10
import 'theme.dart';
11

12
/// A material design card. A card has slightly rounded corners and a shadow.
13 14 15
///
/// A card is a sheet of [Material] used to represent some related information,
/// for example an album, a geographical location, a meal, contact details, etc.
16
///
17 18 19 20 21 22
/// This is what it looks like when run:
///
/// ![A card with a slight shadow, consisting of two rows, one with an icon and
/// some text describing a musical, and the other with buttons for buying
/// tickets or listening to the show.](https://flutter.github.io/assets-for-api-docs/assets/material/card.png)
///
23
/// {@tool dartpad --template=stateless_widget_scaffold}
24
///
25 26
/// This sample shows creation of a [Card] widget that shows album information
/// and two actions.
27 28
///
/// ```dart
29 30 31 32 33 34 35 36 37 38
/// Widget build(BuildContext context) {
///   return Center(
///     child: Card(
///       child: Column(
///         mainAxisSize: MainAxisSize.min,
///         children: <Widget>[
///           const ListTile(
///             leading: Icon(Icons.album),
///             title: Text('The Enchanted Nightingale'),
///             subtitle: Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
39
///           ),
40 41 42 43 44 45 46 47 48 49 50
///           ButtonBar(
///             children: <Widget>[
///               FlatButton(
///                 child: const Text('BUY TICKETS'),
///                 onPressed: () { /* ... */ },
///               ),
///               FlatButton(
///                 child: const Text('LISTEN'),
///                 onPressed: () { /* ... */ },
///               ),
///             ],
51 52 53
///           ),
///         ],
///       ),
54
///     ),
55 56
///   );
/// }
57
/// ```
58
/// {@end-tool}
59
///
60 61 62
/// Sometimes the primary action area of a card is the card itself. Cards can be
/// one large touch target that shows a detail screen when tapped.
///
63
/// {@tool dartpad --template=stateless_widget_scaffold}
64 65 66 67 68 69
///
/// This sample shows creation of a [Card] widget that can be tapped. When
/// tapped this [Card]'s [InkWell] displays an "ink splash" that fills the
/// entire card.
///
/// ```dart
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
/// Widget build(BuildContext context) {
///   return Center(
///     child: Card(
///       child: InkWell(
///         splashColor: Colors.blue.withAlpha(30),
///         onTap: () {
///           print('Card tapped.');
///         },
///         child: Container(
///           width: 300,
///           height: 100,
///           child: Text('A card that can be tapped'),
///         ),
///       ),
///     ),
///   );
/// }
87 88 89 90
/// ```
///
/// {@end-tool}
///
91 92
/// See also:
///
93
///  * [ListTile], to display icons and text in a card.
94
///  * [ButtonBar], to display buttons at the bottom of a card.
95
///  * [showDialog], to display a modal card.
96
///  * <https://material.io/design/components/cards.html>
97
class Card extends StatelessWidget {
98
  /// Creates a material design card.
99
  ///
100 101
  /// The [elevation] must be null or non-negative. The [borderOnForeground]
  /// must not be null.
102 103
  const Card({
    Key key,
104
    this.color,
105
    this.shadowColor,
106
    this.elevation,
Hans Muller's avatar
Hans Muller committed
107
    this.shape,
108
    this.borderOnForeground = true,
109 110
    this.margin,
    this.clipBehavior,
111
    this.child,
112
    this.semanticContainer = true,
113
  }) : assert(elevation == null || elevation >= 0.0),
114
       assert(borderOnForeground != null),
115
       super(key: key);
116

Hans Muller's avatar
Hans Muller committed
117
  /// The card's background color.
118
  ///
Hans Muller's avatar
Hans Muller committed
119 120
  /// Defines the card's [Material.color].
  ///
121 122
  /// If this property is null then [ThemeData.cardTheme.color] is used,
  /// if that's null then [ThemeData.cardColor] is used.
123 124
  final Color color;

125 126 127 128 129 130
  /// The color to paint the shadow below the card.
  ///
  /// If null then the ambient [CardTheme]'s shadowColor is used.
  /// If that's null too, then the default is fully opaque black.
  final Color shadowColor;

131 132
  /// The z-coordinate at which to place this card. This controls the size of
  /// the shadow below the card.
133
  ///
Hans Muller's avatar
Hans Muller committed
134 135
  /// Defines the card's [Material.elevation].
  ///
136 137
  /// If this property is null then [ThemeData.cardTheme.elevation] is used,
  /// if that's null, the default value is 1.0.
138
  final double elevation;
139

Hans Muller's avatar
Hans Muller committed
140 141 142 143
  /// The shape of the card's [Material].
  ///
  /// Defines the card's [Material.shape].
  ///
144 145 146
  /// If this property is null then [ThemeData.cardTheme.shape] is used.
  /// If that's null then the shape will be a [RoundedRectangleBorder] with a
  /// circular corner radius of 4.0.
Hans Muller's avatar
Hans Muller committed
147 148
  final ShapeBorder shape;

149 150 151 152 153 154
  /// Whether to paint the [shape] border in front of the [child].
  ///
  /// The default value is true.
  /// If false, the border will be painted behind the [child].
  final bool borderOnForeground;

155
  /// {@macro flutter.widgets.Clip}
156
  ///
157 158
  /// If this property is null then [ThemeData.cardTheme.clipBehavior] is used.
  /// If that's null then the behavior will be [Clip.none].
159 160
  final Clip clipBehavior;

161 162 163 164
  /// The empty space that surrounds the card.
  ///
  /// Defines the card's outer [Container.margin].
  ///
165 166
  /// If this property is null then [ThemeData.cardTheme.margin] is used,
  /// if that's null, the default margin is 4.0 logical pixels on all sides:
167 168 169
  /// `EdgeInsets.all(4.0)`.
  final EdgeInsetsGeometry margin;

170 171 172
  /// Whether this widget represents a single semantic container, or if false
  /// a collection of individual semantic nodes.
  ///
173
  /// Defaults to true.
174 175 176 177 178 179 180 181 182
  ///
  /// Setting this flag to true will attempt to merge all child semantics into
  /// this node. Setting this flag to false will force all child semantic nodes
  /// to be explicit.
  ///
  /// This flag should be false if the card contains multiple different types
  /// of content.
  final bool semanticContainer;

Hans Muller's avatar
Hans Muller committed
183 184 185 186 187
  /// The widget below this widget in the tree.
  ///
  /// {@macro flutter.widgets.child}
  final Widget child;

188 189
  static const double _defaultElevation = 1.0;

190
  @override
191
  Widget build(BuildContext context) {
192 193
    final CardTheme cardTheme = CardTheme.of(context);

194
    return Semantics(
195
      container: semanticContainer,
196
      child: Container(
197
        margin: margin ?? cardTheme.margin ?? const EdgeInsets.all(4.0),
198
        child: Material(
199
          type: MaterialType.card,
200
          shadowColor: shadowColor ?? cardTheme.shadowColor ?? Colors.black,
201 202 203
          color: color ?? cardTheme.color ?? Theme.of(context).cardColor,
          elevation: elevation ?? cardTheme.elevation ?? _defaultElevation,
          shape: shape ?? cardTheme.shape ?? const RoundedRectangleBorder(
204
            borderRadius: BorderRadius.all(Radius.circular(4.0)),
Hans Muller's avatar
Hans Muller committed
205
          ),
206
          borderOnForeground: borderOnForeground,
207
          clipBehavior: clipBehavior ?? cardTheme.clipBehavior ?? Clip.none,
208 209 210 211
          child: Semantics(
            explicitChildNodes: !semanticContainer,
            child: child,
          ),
Hans Muller's avatar
Hans Muller committed
212
        ),
213
      ),
214 215 216
    );
  }
}