1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// 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.
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/painting.dart';
import 'colors.dart';
import 'debug.dart';
import 'feedback.dart';
import 'icons.dart';
import 'tooltip.dart';
/// A material design chip.
///
/// Chips represent complex entities in small blocks, such as a contact.
///
/// Supplying a non-null [onDeleted] callback will cause the chip to include a
/// button for deleting the chip.
///
/// Requires one of its ancestors to be a [Material] widget. The [label]
/// and [border] arguments must not be null.
///
/// ## Sample code
///
/// ```dart
/// new Chip(
/// avatar: new CircleAvatar(
/// backgroundColor: Colors.grey.shade800,
/// child: new Text('AB'),
/// ),
/// label: new Text('Aaron Burr'),
/// )
/// ```
///
/// See also:
///
/// * [CircleAvatar], which shows images or initials of people.
/// * <https://material.google.com/components/chips.html>
class Chip extends StatelessWidget {
/// Creates a material design chip.
///
/// * [onDeleted] determines whether the chip has a delete button. This
/// callback runs when the delete button is pressed.
const Chip({
Key key,
this.avatar,
@required this.label,
this.onDeleted,
TextStyle labelStyle,
this.deleteButtonTooltipMessage,
this.backgroundColor,
this.deleteIconColor,
this.border: const StadiumBorder(),
}) : assert(label != null),
assert(border != null),
labelStyle = labelStyle ?? _defaultLabelStyle,
super(key: key);
static const TextStyle _defaultLabelStyle = const TextStyle(
inherit: false,
fontSize: 13.0,
fontWeight: FontWeight.w400,
color: Colors.black87,
textBaseline: TextBaseline.alphabetic,
);
static const double _chipHeight = 32.0;
/// A widget to display prior to the chip's label.
///
/// Typically a [CircleAvatar] widget.
final Widget avatar;
/// The primary content of the chip.
///
/// Typically a [Text] widget.
final Widget label;
/// Called when the user deletes the chip, e.g., by tapping the delete button.
///
/// The delete button is included in the chip only if this callback is non-null.
final VoidCallback onDeleted;
/// The style to be applied to the chip's label.
///
/// This only has effect on widgets that respect the [DefaultTextStyle],
/// such as [Text].
final TextStyle labelStyle;
/// Color to be used for the chip's background, the default being grey.
///
/// This color is used as the background of the container that will hold the
/// widget's label.
final Color backgroundColor;
/// The border to draw around the chip.
///
/// Defaults to a [StadiumBorder].
final ShapeBorder border;
/// Color for delete icon, the default being black.
///
/// This has no effect when [onDelete] is null since no delete icon will be
/// shown.
final Color deleteIconColor;
/// Message to be used for the chip delete button's tooltip.
///
/// This has no effect when [onDelete] is null since no delete icon will be
/// shown.
final String deleteButtonTooltipMessage;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final bool deletable = onDeleted != null;
double startPadding = 12.0;
double endPadding = 12.0;
final List<Widget> children = <Widget>[];
if (avatar != null) {
startPadding = 0.0;
children.add(new ExcludeSemantics(
child: new Container(
margin: const EdgeInsetsDirectional.only(end: 8.0),
width: _chipHeight,
height: _chipHeight,
child: avatar,
),
));
}
children.add(new Flexible(
child: new DefaultTextStyle(
overflow: TextOverflow.ellipsis,
style: labelStyle,
child: label,
),
));
if (deletable) {
endPadding = 0.0;
children.add(new GestureDetector(
onTap: Feedback.wrapForTap(onDeleted, context),
child: new Tooltip(
// TODO(gspencer): Internationalize this text.
// https://github.com/flutter/flutter/issues/12378
message: deleteButtonTooltipMessage ?? 'Delete "$label"',
child: new Container(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: new Icon(
Icons.cancel,
size: 24.0,
color: deleteIconColor ?? Colors.black54,
),
),
),
));
}
return new Semantics(
container: true,
child: new Container(
constraints: const BoxConstraints(minHeight: _chipHeight),
padding: new EdgeInsetsDirectional.only(start: startPadding, end: endPadding),
decoration: new ShapeDecoration(
color: backgroundColor ?? Colors.grey.shade300,
shape: border,
),
child: new Center(
widthFactor: 1.0,
heightFactor: 1.0,
child: new Row(
children: children,
mainAxisSize: MainAxisSize.min,
),
),
),
);
}
}