Refactor chip class and move independent chips into separate classes (#101507)
This commit is contained in:
parent
0675471207
commit
0f2b1a3baf
@ -45,6 +45,10 @@ export 'src/material/checkbox.dart';
|
||||
export 'src/material/checkbox_list_tile.dart';
|
||||
export 'src/material/checkbox_theme.dart';
|
||||
export 'src/material/chip.dart';
|
||||
export 'src/material/chip_action.dart';
|
||||
export 'src/material/chip_choice.dart';
|
||||
export 'src/material/chip_filter.dart';
|
||||
export 'src/material/chip_input.dart';
|
||||
export 'src/material/chip_theme.dart';
|
||||
export 'src/material/circle_avatar.dart';
|
||||
export 'src/material/color_scheme.dart';
|
||||
|
@ -659,777 +659,6 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
|
||||
}
|
||||
}
|
||||
|
||||
/// A material design input chip.
|
||||
///
|
||||
/// Input chips represent a complex piece of information, such as an entity
|
||||
/// (person, place, or thing) or conversational text, in a compact form.
|
||||
///
|
||||
/// Input chips can be made selectable by setting [onSelected], deletable by
|
||||
/// setting [onDeleted], and pressable like a button with [onPressed]. They have
|
||||
/// a [label], and they can have a leading icon (see [avatar]) and a trailing
|
||||
/// icon ([deleteIcon]). Colors and padding can be customized.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget.
|
||||
///
|
||||
/// Input chips work together with other UI elements. They can appear:
|
||||
///
|
||||
/// * In a [Wrap] widget.
|
||||
/// * In a horizontally scrollable list, like a [ListView] whose
|
||||
/// scrollDirection is [Axis.horizontal].
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// InputChip(
|
||||
/// avatar: CircleAvatar(
|
||||
/// backgroundColor: Colors.grey.shade800,
|
||||
/// child: const Text('AB'),
|
||||
/// ),
|
||||
/// label: const Text('Aaron Burr'),
|
||||
/// onPressed: () {
|
||||
/// print('I am the one thing in life.');
|
||||
/// }
|
||||
/// )
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [ChoiceChip], allows a single selection from a set of options. Choice
|
||||
/// chips contain related descriptive text or categories.
|
||||
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
|
||||
/// * [ActionChip], represents an action related to primary content.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class InputChip extends StatelessWidget
|
||||
implements
|
||||
ChipAttributes,
|
||||
DeletableChipAttributes,
|
||||
SelectableChipAttributes,
|
||||
CheckmarkableChipAttributes,
|
||||
DisabledChipAttributes,
|
||||
TappableChipAttributes {
|
||||
/// Creates an [InputChip].
|
||||
///
|
||||
/// The [onPressed] and [onSelected] callbacks must not both be specified at
|
||||
/// the same time.
|
||||
///
|
||||
/// The [label], [isEnabled], [selected], [autofocus], and [clipBehavior]
|
||||
/// arguments must not be null. The [pressElevation] and [elevation] must be
|
||||
/// null or non-negative. Typically, [pressElevation] is greater than
|
||||
/// [elevation].
|
||||
const InputChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
this.selected = false,
|
||||
this.isEnabled = true,
|
||||
this.onSelected,
|
||||
this.deleteIcon,
|
||||
this.onDeleted,
|
||||
this.deleteIconColor,
|
||||
this.deleteButtonTooltipMessage,
|
||||
this.onPressed,
|
||||
this.pressElevation,
|
||||
this.disabledColor,
|
||||
this.selectedColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.selectedShadowColor,
|
||||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
@Deprecated(
|
||||
'Migrate to deleteButtonTooltipMessage. '
|
||||
'This feature was deprecated after v2.10.0-0.3.pre.'
|
||||
)
|
||||
this.useDeleteButtonTooltip = true,
|
||||
}) : assert(selected != null),
|
||||
assert(isEnabled != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final bool selected;
|
||||
@override
|
||||
final bool isEnabled;
|
||||
@override
|
||||
final ValueChanged<bool>? onSelected;
|
||||
@override
|
||||
final Widget? deleteIcon;
|
||||
@override
|
||||
final VoidCallback? onDeleted;
|
||||
@override
|
||||
final Color? deleteIconColor;
|
||||
@override
|
||||
final String? deleteButtonTooltipMessage;
|
||||
@override
|
||||
final VoidCallback? onPressed;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final Color? disabledColor;
|
||||
@override
|
||||
final Color? selectedColor;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
@override
|
||||
final Color? selectedShadowColor;
|
||||
@override
|
||||
final bool? showCheckmark;
|
||||
@override
|
||||
final Color? checkmarkColor;
|
||||
@override
|
||||
final ShapeBorder avatarBorder;
|
||||
@override
|
||||
@Deprecated(
|
||||
'Migrate to deleteButtonTooltipMessage. '
|
||||
'This feature was deprecated after v2.10.0-0.3.pre.'
|
||||
)
|
||||
final bool useDeleteButtonTooltip;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
labelStyle: labelStyle,
|
||||
labelPadding: labelPadding,
|
||||
deleteIcon: deleteIcon,
|
||||
onDeleted: onDeleted,
|
||||
deleteIconColor: deleteIconColor,
|
||||
useDeleteButtonTooltip: useDeleteButtonTooltip,
|
||||
deleteButtonTooltipMessage: deleteButtonTooltipMessage,
|
||||
onSelected: onSelected,
|
||||
onPressed: onPressed,
|
||||
pressElevation: pressElevation,
|
||||
selected: selected,
|
||||
disabledColor: disabledColor,
|
||||
selectedColor: selectedColor,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
backgroundColor: backgroundColor,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
selectedShadowColor: selectedShadowColor,
|
||||
showCheckmark: showCheckmark,
|
||||
checkmarkColor: checkmarkColor,
|
||||
isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null),
|
||||
avatarBorder: avatarBorder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A material design choice chip.
|
||||
///
|
||||
/// [ChoiceChip]s represent a single choice from a set. Choice chips contain
|
||||
/// related descriptive text or categories.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget. The [selected] and
|
||||
/// [label] arguments must not be null.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// class MyThreeOptions extends StatefulWidget {
|
||||
/// const MyThreeOptions({Key? key}) : super(key: key);
|
||||
///
|
||||
/// @override
|
||||
/// State<MyThreeOptions> createState() => _MyThreeOptionsState();
|
||||
/// }
|
||||
///
|
||||
/// class _MyThreeOptionsState extends State<MyThreeOptions> {
|
||||
/// int? _value = 1;
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return Wrap(
|
||||
/// children: List<Widget>.generate(
|
||||
/// 3,
|
||||
/// (int index) {
|
||||
/// return ChoiceChip(
|
||||
/// label: Text('Item $index'),
|
||||
/// selected: _value == index,
|
||||
/// onSelected: (bool selected) {
|
||||
/// setState(() {
|
||||
/// _value = selected ? index : null;
|
||||
/// });
|
||||
/// },
|
||||
/// );
|
||||
/// },
|
||||
/// ).toList(),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [InputChip], a chip that represents a complex piece of information, such
|
||||
/// as an entity (person, place, or thing) or conversational text, in a
|
||||
/// compact form.
|
||||
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
|
||||
/// * [ActionChip], represents an action related to primary content.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class ChoiceChip extends StatelessWidget
|
||||
implements
|
||||
ChipAttributes,
|
||||
SelectableChipAttributes,
|
||||
DisabledChipAttributes {
|
||||
/// Create a chip that acts like a radio button.
|
||||
///
|
||||
/// The [label], [selected], [autofocus], and [clipBehavior] arguments must
|
||||
/// not be null. The [pressElevation] and [elevation] must be null or
|
||||
/// non-negative. Typically, [pressElevation] is greater than [elevation].
|
||||
const ChoiceChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
this.onSelected,
|
||||
this.pressElevation,
|
||||
required this.selected,
|
||||
this.selectedColor,
|
||||
this.disabledColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.selectedShadowColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
}) : assert(selected != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final ValueChanged<bool>? onSelected;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final bool selected;
|
||||
@override
|
||||
final Color? disabledColor;
|
||||
@override
|
||||
final Color? selectedColor;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
@override
|
||||
final Color? selectedShadowColor;
|
||||
@override
|
||||
final ShapeBorder avatarBorder;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
final ChipThemeData chipTheme = ChipTheme.of(context);
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
labelStyle: labelStyle ?? (selected ? chipTheme.secondaryLabelStyle : null),
|
||||
labelPadding: labelPadding,
|
||||
onSelected: onSelected,
|
||||
pressElevation: pressElevation,
|
||||
selected: selected,
|
||||
showCheckmark: false,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
disabledColor: disabledColor,
|
||||
selectedColor: selectedColor ?? chipTheme.secondarySelectedColor,
|
||||
backgroundColor: backgroundColor,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
isEnabled: isEnabled,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
selectedShadowColor: selectedShadowColor,
|
||||
avatarBorder: avatarBorder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A material design filter chip.
|
||||
///
|
||||
/// Filter chips use tags or descriptive words as a way to filter content.
|
||||
///
|
||||
/// Filter chips are a good alternative to [Checkbox] or [Switch] widgets.
|
||||
/// Unlike these alternatives, filter chips allow for clearly delineated and
|
||||
/// exposed options in a compact area.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// class ActorFilterEntry {
|
||||
/// const ActorFilterEntry(this.name, this.initials);
|
||||
/// final String name;
|
||||
/// final String initials;
|
||||
/// }
|
||||
///
|
||||
/// class CastFilter extends StatefulWidget {
|
||||
/// const CastFilter({Key? key}) : super(key: key);
|
||||
///
|
||||
/// @override
|
||||
/// State createState() => CastFilterState();
|
||||
/// }
|
||||
///
|
||||
/// class CastFilterState extends State<CastFilter> {
|
||||
/// final List<ActorFilterEntry> _cast = <ActorFilterEntry>[
|
||||
/// const ActorFilterEntry('Aaron Burr', 'AB'),
|
||||
/// const ActorFilterEntry('Alexander Hamilton', 'AH'),
|
||||
/// const ActorFilterEntry('Eliza Hamilton', 'EH'),
|
||||
/// const ActorFilterEntry('James Madison', 'JM'),
|
||||
/// ];
|
||||
/// final List<String> _filters = <String>[];
|
||||
///
|
||||
/// Iterable<Widget> get actorWidgets {
|
||||
/// return _cast.map((ActorFilterEntry actor) {
|
||||
/// return Padding(
|
||||
/// padding: const EdgeInsets.all(4.0),
|
||||
/// child: FilterChip(
|
||||
/// avatar: CircleAvatar(child: Text(actor.initials)),
|
||||
/// label: Text(actor.name),
|
||||
/// selected: _filters.contains(actor.name),
|
||||
/// onSelected: (bool value) {
|
||||
/// setState(() {
|
||||
/// if (value) {
|
||||
/// _filters.add(actor.name);
|
||||
/// } else {
|
||||
/// _filters.removeWhere((String name) {
|
||||
/// return name == actor.name;
|
||||
/// });
|
||||
/// }
|
||||
/// });
|
||||
/// },
|
||||
/// ),
|
||||
/// );
|
||||
/// });
|
||||
/// }
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return Column(
|
||||
/// mainAxisAlignment: MainAxisAlignment.center,
|
||||
/// children: <Widget>[
|
||||
/// Wrap(
|
||||
/// children: actorWidgets.toList(),
|
||||
/// ),
|
||||
/// Text('Look for: ${_filters.join(', ')}'),
|
||||
/// ],
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [InputChip], a chip that represents a complex piece of information, such
|
||||
/// as an entity (person, place, or thing) or conversational text, in a
|
||||
/// compact form.
|
||||
/// * [ChoiceChip], allows a single selection from a set of options. Choice
|
||||
/// chips contain related descriptive text or categories.
|
||||
/// * [ActionChip], represents an action related to primary content.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class FilterChip extends StatelessWidget
|
||||
implements
|
||||
ChipAttributes,
|
||||
SelectableChipAttributes,
|
||||
CheckmarkableChipAttributes,
|
||||
DisabledChipAttributes {
|
||||
/// Create a chip that acts like a checkbox.
|
||||
///
|
||||
/// The [selected], [label], [autofocus], and [clipBehavior] arguments must
|
||||
/// not be null. The [pressElevation] and [elevation] must be null or
|
||||
/// non-negative. Typically, [pressElevation] is greater than [elevation].
|
||||
const FilterChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
this.selected = false,
|
||||
required this.onSelected,
|
||||
this.pressElevation,
|
||||
this.disabledColor,
|
||||
this.selectedColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.selectedShadowColor,
|
||||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
}) : assert(selected != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final bool selected;
|
||||
@override
|
||||
final ValueChanged<bool>? onSelected;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final Color? disabledColor;
|
||||
@override
|
||||
final Color? selectedColor;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
@override
|
||||
final Color? selectedShadowColor;
|
||||
@override
|
||||
final bool? showCheckmark;
|
||||
@override
|
||||
final Color? checkmarkColor;
|
||||
@override
|
||||
final ShapeBorder avatarBorder;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
labelStyle: labelStyle,
|
||||
labelPadding: labelPadding,
|
||||
onSelected: onSelected,
|
||||
pressElevation: pressElevation,
|
||||
selected: selected,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
backgroundColor: backgroundColor,
|
||||
disabledColor: disabledColor,
|
||||
selectedColor: selectedColor,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
isEnabled: isEnabled,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
selectedShadowColor: selectedShadowColor,
|
||||
showCheckmark: showCheckmark,
|
||||
checkmarkColor: checkmarkColor,
|
||||
avatarBorder: avatarBorder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A material design action chip.
|
||||
///
|
||||
/// Action chips are a set of options which trigger an action related to primary
|
||||
/// content. Action chips should appear dynamically and contextually in a UI.
|
||||
///
|
||||
/// Action chips can be tapped to trigger an action or show progress and
|
||||
/// confirmation. They cannot be disabled; if the action is not applicable, the
|
||||
/// chip should not be included in the interface. (This contrasts with buttons,
|
||||
/// where unavailable choices are usually represented as disabled controls.)
|
||||
///
|
||||
/// Action chips are displayed after primary content, such as below a card or
|
||||
/// persistently at the bottom of a screen.
|
||||
///
|
||||
/// The material button widgets, [ElevatedButton], [TextButton], and
|
||||
/// [OutlinedButton], are an alternative to action chips, which should appear
|
||||
/// statically and consistently in a UI.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// ActionChip(
|
||||
/// avatar: CircleAvatar(
|
||||
/// backgroundColor: Colors.grey.shade800,
|
||||
/// child: const Text('AB'),
|
||||
/// ),
|
||||
/// label: const Text('Aaron Burr'),
|
||||
/// onPressed: () {
|
||||
/// print('If you stand for nothing, Burr, what’ll you fall for?');
|
||||
/// }
|
||||
/// )
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [InputChip], a chip that represents a complex piece of information, such
|
||||
/// as an entity (person, place, or thing) or conversational text, in a
|
||||
/// compact form.
|
||||
/// * [ChoiceChip], allows a single selection from a set of options. Choice
|
||||
/// chips contain related descriptive text or categories.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class ActionChip extends StatelessWidget implements ChipAttributes, TappableChipAttributes {
|
||||
/// Create a chip that acts like a button.
|
||||
///
|
||||
/// The [label], [onPressed], [autofocus], and [clipBehavior] arguments must
|
||||
/// not be null. The [pressElevation] and [elevation] must be null or
|
||||
/// non-negative. Typically, [pressElevation] is greater than [elevation].
|
||||
const ActionChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
required this.onPressed,
|
||||
this.pressElevation,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
}) : assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(
|
||||
onPressed != null,
|
||||
'Rather than disabling an ActionChip by setting onPressed to null, '
|
||||
'remove it from the interface entirely.',
|
||||
),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final VoidCallback onPressed;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
onPressed: onPressed,
|
||||
pressElevation: pressElevation,
|
||||
tooltip: tooltip,
|
||||
labelStyle: labelStyle,
|
||||
backgroundColor: backgroundColor,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
labelPadding: labelPadding,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A raw material design chip.
|
||||
///
|
||||
/// This serves as the basis for all of the chip widget types to aggregate.
|
||||
|
157
packages/flutter/lib/src/material/chip_action.dart
Normal file
157
packages/flutter/lib/src/material/chip_action.dart
Normal file
@ -0,0 +1,157 @@
|
||||
// Copyright 2014 The Flutter 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/widgets.dart';
|
||||
|
||||
import 'chip.dart';
|
||||
import 'debug.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// A material design action chip.
|
||||
///
|
||||
/// Action chips are a set of options which trigger an action related to primary
|
||||
/// content. Action chips should appear dynamically and contextually in a UI.
|
||||
///
|
||||
/// Action chips can be tapped to trigger an action or show progress and
|
||||
/// confirmation. They cannot be disabled; if the action is not applicable, the
|
||||
/// chip should not be included in the interface. (This contrasts with buttons,
|
||||
/// where unavailable choices are usually represented as disabled controls.)
|
||||
///
|
||||
/// Action chips are displayed after primary content, such as below a card or
|
||||
/// persistently at the bottom of a screen.
|
||||
///
|
||||
/// The material button widgets, [ElevatedButton], [TextButton], and
|
||||
/// [OutlinedButton], are an alternative to action chips, which should appear
|
||||
/// statically and consistently in a UI.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// ActionChip(
|
||||
/// avatar: CircleAvatar(
|
||||
/// backgroundColor: Colors.grey.shade800,
|
||||
/// child: const Text('AB'),
|
||||
/// ),
|
||||
/// label: const Text('Aaron Burr'),
|
||||
/// onPressed: () {
|
||||
/// print('If you stand for nothing, Burr, what’ll you fall for?');
|
||||
/// }
|
||||
/// )
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [InputChip], a chip that represents a complex piece of information, such
|
||||
/// as an entity (person, place, or thing) or conversational text, in a
|
||||
/// compact form.
|
||||
/// * [ChoiceChip], allows a single selection from a set of options. Choice
|
||||
/// chips contain related descriptive text or categories.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class ActionChip extends StatelessWidget implements ChipAttributes, TappableChipAttributes {
|
||||
/// Create a chip that acts like a button.
|
||||
///
|
||||
/// The [label], [onPressed], [autofocus], and [clipBehavior] arguments must
|
||||
/// not be null. The [pressElevation] and [elevation] must be null or
|
||||
/// non-negative. Typically, [pressElevation] is greater than [elevation].
|
||||
const ActionChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
required this.onPressed,
|
||||
this.pressElevation,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
}) : assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(
|
||||
onPressed != null,
|
||||
'Rather than disabling an ActionChip by setting onPressed to null, '
|
||||
'remove it from the interface entirely.',
|
||||
),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final VoidCallback onPressed;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
onPressed: onPressed,
|
||||
pressElevation: pressElevation,
|
||||
tooltip: tooltip,
|
||||
labelStyle: labelStyle,
|
||||
backgroundColor: backgroundColor,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
labelPadding: labelPadding,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
);
|
||||
}
|
||||
}
|
193
packages/flutter/lib/src/material/chip_choice.dart
Normal file
193
packages/flutter/lib/src/material/chip_choice.dart
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright 2014 The Flutter 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/widgets.dart';
|
||||
|
||||
import 'chip.dart';
|
||||
import 'chip_theme.dart';
|
||||
import 'debug.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// A material design choice chip.
|
||||
///
|
||||
/// [ChoiceChip]s represent a single choice from a set. Choice chips contain
|
||||
/// related descriptive text or categories.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget. The [selected] and
|
||||
/// [label] arguments must not be null.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// class MyThreeOptions extends StatefulWidget {
|
||||
/// const MyThreeOptions({Key? key}) : super(key: key);
|
||||
///
|
||||
/// @override
|
||||
/// State<MyThreeOptions> createState() => _MyThreeOptionsState();
|
||||
/// }
|
||||
///
|
||||
/// class _MyThreeOptionsState extends State<MyThreeOptions> {
|
||||
/// int? _value = 1;
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return Wrap(
|
||||
/// children: List<Widget>.generate(
|
||||
/// 3,
|
||||
/// (int index) {
|
||||
/// return ChoiceChip(
|
||||
/// label: Text('Item $index'),
|
||||
/// selected: _value == index,
|
||||
/// onSelected: (bool selected) {
|
||||
/// setState(() {
|
||||
/// _value = selected ? index : null;
|
||||
/// });
|
||||
/// },
|
||||
/// );
|
||||
/// },
|
||||
/// ).toList(),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [InputChip], a chip that represents a complex piece of information, such
|
||||
/// as an entity (person, place, or thing) or conversational text, in a
|
||||
/// compact form.
|
||||
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
|
||||
/// * [ActionChip], represents an action related to primary content.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class ChoiceChip extends StatelessWidget
|
||||
implements
|
||||
ChipAttributes,
|
||||
SelectableChipAttributes,
|
||||
DisabledChipAttributes {
|
||||
/// Create a chip that acts like a radio button.
|
||||
///
|
||||
/// The [label], [selected], [autofocus], and [clipBehavior] arguments must
|
||||
/// not be null. The [pressElevation] and [elevation] must be null or
|
||||
/// non-negative. Typically, [pressElevation] is greater than [elevation].
|
||||
const ChoiceChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
this.onSelected,
|
||||
this.pressElevation,
|
||||
required this.selected,
|
||||
this.selectedColor,
|
||||
this.disabledColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.selectedShadowColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
}) : assert(selected != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final ValueChanged<bool>? onSelected;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final bool selected;
|
||||
@override
|
||||
final Color? disabledColor;
|
||||
@override
|
||||
final Color? selectedColor;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
@override
|
||||
final Color? selectedShadowColor;
|
||||
@override
|
||||
final ShapeBorder avatarBorder;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
final ChipThemeData chipTheme = ChipTheme.of(context);
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
labelStyle: labelStyle ?? (selected ? chipTheme.secondaryLabelStyle : null),
|
||||
labelPadding: labelPadding,
|
||||
onSelected: onSelected,
|
||||
pressElevation: pressElevation,
|
||||
selected: selected,
|
||||
showCheckmark: false,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
disabledColor: disabledColor,
|
||||
selectedColor: selectedColor ?? chipTheme.secondarySelectedColor,
|
||||
backgroundColor: backgroundColor,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
isEnabled: isEnabled,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
selectedShadowColor: selectedShadowColor,
|
||||
avatarBorder: avatarBorder,
|
||||
);
|
||||
}
|
||||
}
|
231
packages/flutter/lib/src/material/chip_filter.dart
Normal file
231
packages/flutter/lib/src/material/chip_filter.dart
Normal file
@ -0,0 +1,231 @@
|
||||
// Copyright 2014 The Flutter 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/widgets.dart';
|
||||
|
||||
import 'chip.dart';
|
||||
import 'debug.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// A material design filter chip.
|
||||
///
|
||||
/// Filter chips use tags or descriptive words as a way to filter content.
|
||||
///
|
||||
/// Filter chips are a good alternative to [Checkbox] or [Switch] widgets.
|
||||
/// Unlike these alternatives, filter chips allow for clearly delineated and
|
||||
/// exposed options in a compact area.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// class ActorFilterEntry {
|
||||
/// const ActorFilterEntry(this.name, this.initials);
|
||||
/// final String name;
|
||||
/// final String initials;
|
||||
/// }
|
||||
///
|
||||
/// class CastFilter extends StatefulWidget {
|
||||
/// const CastFilter({Key? key}) : super(key: key);
|
||||
///
|
||||
/// @override
|
||||
/// State createState() => CastFilterState();
|
||||
/// }
|
||||
///
|
||||
/// class CastFilterState extends State<CastFilter> {
|
||||
/// final List<ActorFilterEntry> _cast = <ActorFilterEntry>[
|
||||
/// const ActorFilterEntry('Aaron Burr', 'AB'),
|
||||
/// const ActorFilterEntry('Alexander Hamilton', 'AH'),
|
||||
/// const ActorFilterEntry('Eliza Hamilton', 'EH'),
|
||||
/// const ActorFilterEntry('James Madison', 'JM'),
|
||||
/// ];
|
||||
/// final List<String> _filters = <String>[];
|
||||
///
|
||||
/// Iterable<Widget> get actorWidgets {
|
||||
/// return _cast.map((ActorFilterEntry actor) {
|
||||
/// return Padding(
|
||||
/// padding: const EdgeInsets.all(4.0),
|
||||
/// child: FilterChip(
|
||||
/// avatar: CircleAvatar(child: Text(actor.initials)),
|
||||
/// label: Text(actor.name),
|
||||
/// selected: _filters.contains(actor.name),
|
||||
/// onSelected: (bool value) {
|
||||
/// setState(() {
|
||||
/// if (value) {
|
||||
/// _filters.add(actor.name);
|
||||
/// } else {
|
||||
/// _filters.removeWhere((String name) {
|
||||
/// return name == actor.name;
|
||||
/// });
|
||||
/// }
|
||||
/// });
|
||||
/// },
|
||||
/// ),
|
||||
/// );
|
||||
/// });
|
||||
/// }
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return Column(
|
||||
/// mainAxisAlignment: MainAxisAlignment.center,
|
||||
/// children: <Widget>[
|
||||
/// Wrap(
|
||||
/// children: actorWidgets.toList(),
|
||||
/// ),
|
||||
/// Text('Look for: ${_filters.join(', ')}'),
|
||||
/// ],
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [InputChip], a chip that represents a complex piece of information, such
|
||||
/// as an entity (person, place, or thing) or conversational text, in a
|
||||
/// compact form.
|
||||
/// * [ChoiceChip], allows a single selection from a set of options. Choice
|
||||
/// chips contain related descriptive text or categories.
|
||||
/// * [ActionChip], represents an action related to primary content.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class FilterChip extends StatelessWidget
|
||||
implements
|
||||
ChipAttributes,
|
||||
SelectableChipAttributes,
|
||||
CheckmarkableChipAttributes,
|
||||
DisabledChipAttributes {
|
||||
/// Create a chip that acts like a checkbox.
|
||||
///
|
||||
/// The [selected], [label], [autofocus], and [clipBehavior] arguments must
|
||||
/// not be null. The [pressElevation] and [elevation] must be null or
|
||||
/// non-negative. Typically, [pressElevation] is greater than [elevation].
|
||||
const FilterChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
this.selected = false,
|
||||
required this.onSelected,
|
||||
this.pressElevation,
|
||||
this.disabledColor,
|
||||
this.selectedColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.selectedShadowColor,
|
||||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
}) : assert(selected != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final bool selected;
|
||||
@override
|
||||
final ValueChanged<bool>? onSelected;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final Color? disabledColor;
|
||||
@override
|
||||
final Color? selectedColor;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
@override
|
||||
final Color? selectedShadowColor;
|
||||
@override
|
||||
final bool? showCheckmark;
|
||||
@override
|
||||
final Color? checkmarkColor;
|
||||
@override
|
||||
final ShapeBorder avatarBorder;
|
||||
|
||||
@override
|
||||
bool get isEnabled => onSelected != null;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
labelStyle: labelStyle,
|
||||
labelPadding: labelPadding,
|
||||
onSelected: onSelected,
|
||||
pressElevation: pressElevation,
|
||||
selected: selected,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
backgroundColor: backgroundColor,
|
||||
disabledColor: disabledColor,
|
||||
selectedColor: selectedColor,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
isEnabled: isEnabled,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
selectedShadowColor: selectedShadowColor,
|
||||
showCheckmark: showCheckmark,
|
||||
checkmarkColor: checkmarkColor,
|
||||
avatarBorder: avatarBorder,
|
||||
);
|
||||
}
|
||||
}
|
227
packages/flutter/lib/src/material/chip_input.dart
Normal file
227
packages/flutter/lib/src/material/chip_input.dart
Normal file
@ -0,0 +1,227 @@
|
||||
// Copyright 2014 The Flutter 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/widgets.dart';
|
||||
|
||||
import 'chip.dart';
|
||||
import 'debug.dart';
|
||||
import 'theme_data.dart';
|
||||
|
||||
/// A material design input chip.
|
||||
///
|
||||
/// Input chips represent a complex piece of information, such as an entity
|
||||
/// (person, place, or thing) or conversational text, in a compact form.
|
||||
///
|
||||
/// Input chips can be made selectable by setting [onSelected], deletable by
|
||||
/// setting [onDeleted], and pressable like a button with [onPressed]. They have
|
||||
/// a [label], and they can have a leading icon (see [avatar]) and a trailing
|
||||
/// icon ([deleteIcon]). Colors and padding can be customized.
|
||||
///
|
||||
/// Requires one of its ancestors to be a [Material] widget.
|
||||
///
|
||||
/// Input chips work together with other UI elements. They can appear:
|
||||
///
|
||||
/// * In a [Wrap] widget.
|
||||
/// * In a horizontally scrollable list, like a [ListView] whose
|
||||
/// scrollDirection is [Axis.horizontal].
|
||||
///
|
||||
/// {@tool snippet}
|
||||
///
|
||||
/// ```dart
|
||||
/// InputChip(
|
||||
/// avatar: CircleAvatar(
|
||||
/// backgroundColor: Colors.grey.shade800,
|
||||
/// child: const Text('AB'),
|
||||
/// ),
|
||||
/// label: const Text('Aaron Burr'),
|
||||
/// onPressed: () {
|
||||
/// print('I am the one thing in life.');
|
||||
/// }
|
||||
/// )
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Chip], a chip that displays information and can be deleted.
|
||||
/// * [ChoiceChip], allows a single selection from a set of options. Choice
|
||||
/// chips contain related descriptive text or categories.
|
||||
/// * [FilterChip], uses tags or descriptive words as a way to filter content.
|
||||
/// * [ActionChip], represents an action related to primary content.
|
||||
/// * [CircleAvatar], which shows images or initials of people.
|
||||
/// * [Wrap], A widget that displays its children in multiple horizontal or
|
||||
/// vertical runs.
|
||||
/// * <https://material.io/design/components/chips.html>
|
||||
class InputChip extends StatelessWidget
|
||||
implements
|
||||
ChipAttributes,
|
||||
DeletableChipAttributes,
|
||||
SelectableChipAttributes,
|
||||
CheckmarkableChipAttributes,
|
||||
DisabledChipAttributes,
|
||||
TappableChipAttributes {
|
||||
/// Creates an [InputChip].
|
||||
///
|
||||
/// The [onPressed] and [onSelected] callbacks must not both be specified at
|
||||
/// the same time.
|
||||
///
|
||||
/// The [label], [isEnabled], [selected], [autofocus], and [clipBehavior]
|
||||
/// arguments must not be null. The [pressElevation] and [elevation] must be
|
||||
/// null or non-negative. Typically, [pressElevation] is greater than
|
||||
/// [elevation].
|
||||
const InputChip({
|
||||
Key? key,
|
||||
this.avatar,
|
||||
required this.label,
|
||||
this.labelStyle,
|
||||
this.labelPadding,
|
||||
this.selected = false,
|
||||
this.isEnabled = true,
|
||||
this.onSelected,
|
||||
this.deleteIcon,
|
||||
this.onDeleted,
|
||||
this.deleteIconColor,
|
||||
this.deleteButtonTooltipMessage,
|
||||
this.onPressed,
|
||||
this.pressElevation,
|
||||
this.disabledColor,
|
||||
this.selectedColor,
|
||||
this.tooltip,
|
||||
this.side,
|
||||
this.shape,
|
||||
this.clipBehavior = Clip.none,
|
||||
this.focusNode,
|
||||
this.autofocus = false,
|
||||
this.backgroundColor,
|
||||
this.padding,
|
||||
this.visualDensity,
|
||||
this.materialTapTargetSize,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.selectedShadowColor,
|
||||
this.showCheckmark,
|
||||
this.checkmarkColor,
|
||||
this.avatarBorder = const CircleBorder(),
|
||||
@Deprecated(
|
||||
'Migrate to deleteButtonTooltipMessage. '
|
||||
'This feature was deprecated after v2.10.0-0.3.pre.'
|
||||
)
|
||||
this.useDeleteButtonTooltip = true,
|
||||
}) : assert(selected != null),
|
||||
assert(isEnabled != null),
|
||||
assert(label != null),
|
||||
assert(clipBehavior != null),
|
||||
assert(autofocus != null),
|
||||
assert(pressElevation == null || pressElevation >= 0.0),
|
||||
assert(elevation == null || elevation >= 0.0),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
final Widget? avatar;
|
||||
@override
|
||||
final Widget label;
|
||||
@override
|
||||
final TextStyle? labelStyle;
|
||||
@override
|
||||
final EdgeInsetsGeometry? labelPadding;
|
||||
@override
|
||||
final bool selected;
|
||||
@override
|
||||
final bool isEnabled;
|
||||
@override
|
||||
final ValueChanged<bool>? onSelected;
|
||||
@override
|
||||
final Widget? deleteIcon;
|
||||
@override
|
||||
final VoidCallback? onDeleted;
|
||||
@override
|
||||
final Color? deleteIconColor;
|
||||
@override
|
||||
final String? deleteButtonTooltipMessage;
|
||||
@override
|
||||
final VoidCallback? onPressed;
|
||||
@override
|
||||
final double? pressElevation;
|
||||
@override
|
||||
final Color? disabledColor;
|
||||
@override
|
||||
final Color? selectedColor;
|
||||
@override
|
||||
final String? tooltip;
|
||||
@override
|
||||
final BorderSide? side;
|
||||
@override
|
||||
final OutlinedBorder? shape;
|
||||
@override
|
||||
final Clip clipBehavior;
|
||||
@override
|
||||
final FocusNode? focusNode;
|
||||
@override
|
||||
final bool autofocus;
|
||||
@override
|
||||
final Color? backgroundColor;
|
||||
@override
|
||||
final EdgeInsetsGeometry? padding;
|
||||
@override
|
||||
final VisualDensity? visualDensity;
|
||||
@override
|
||||
final MaterialTapTargetSize? materialTapTargetSize;
|
||||
@override
|
||||
final double? elevation;
|
||||
@override
|
||||
final Color? shadowColor;
|
||||
@override
|
||||
final Color? selectedShadowColor;
|
||||
@override
|
||||
final bool? showCheckmark;
|
||||
@override
|
||||
final Color? checkmarkColor;
|
||||
@override
|
||||
final ShapeBorder avatarBorder;
|
||||
@override
|
||||
@Deprecated(
|
||||
'Migrate to deleteButtonTooltipMessage. '
|
||||
'This feature was deprecated after v2.10.0-0.3.pre.'
|
||||
)
|
||||
final bool useDeleteButtonTooltip;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
return RawChip(
|
||||
avatar: avatar,
|
||||
label: label,
|
||||
labelStyle: labelStyle,
|
||||
labelPadding: labelPadding,
|
||||
deleteIcon: deleteIcon,
|
||||
onDeleted: onDeleted,
|
||||
deleteIconColor: deleteIconColor,
|
||||
useDeleteButtonTooltip: useDeleteButtonTooltip,
|
||||
deleteButtonTooltipMessage: deleteButtonTooltipMessage,
|
||||
onSelected: onSelected,
|
||||
onPressed: onPressed,
|
||||
pressElevation: pressElevation,
|
||||
selected: selected,
|
||||
disabledColor: disabledColor,
|
||||
selectedColor: selectedColor,
|
||||
tooltip: tooltip,
|
||||
side: side,
|
||||
shape: shape,
|
||||
clipBehavior: clipBehavior,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus,
|
||||
backgroundColor: backgroundColor,
|
||||
padding: padding,
|
||||
visualDensity: visualDensity,
|
||||
materialTapTargetSize: materialTapTargetSize,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
selectedShadowColor: selectedShadowColor,
|
||||
showCheckmark: showCheckmark,
|
||||
checkmarkColor: checkmarkColor,
|
||||
isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null),
|
||||
avatarBorder: avatarBorder,
|
||||
);
|
||||
}
|
||||
}
|
61
packages/flutter/test/material/chip_action_test.dart
Normal file
61
packages/flutter/test/material/chip_action_test.dart
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// Adds the basic requirements for a Chip.
|
||||
Widget wrapForChip({
|
||||
required Widget child,
|
||||
TextDirection textDirection = TextDirection.ltr,
|
||||
double textScaleFactor = 1.0,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(brightness: brightness),
|
||||
home: Directionality(
|
||||
textDirection: textDirection,
|
||||
child: MediaQuery(
|
||||
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
|
||||
child: Material(child: child),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
|
||||
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
|
||||
// There should be two Material widgets, first Material is from the "_wrapForChip" and
|
||||
// last Material is from the "RawChip".
|
||||
expect(materials.length, 2);
|
||||
// The last Material from `RawChip` should have the clip behavior.
|
||||
expect(materials.last.clipBehavior, clipBehavior);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('ActionChip can be tapped', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: ActionChip(
|
||||
onPressed: () { },
|
||||
label: const Text('action chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(ActionChip));
|
||||
expect(tester.takeException(), null);
|
||||
});
|
||||
|
||||
testWidgets('ActionChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(wrapForChip(child: ActionChip(label: label, onPressed: () { })));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(wrapForChip(child: ActionChip(label: label, clipBehavior: Clip.antiAlias, onPressed: () { })));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
}
|
123
packages/flutter/test/material/chip_choice_test.dart
Normal file
123
packages/flutter/test/material/chip_choice_test.dart
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../rendering/mock_canvas.dart';
|
||||
|
||||
RenderBox getMaterialBox(WidgetTester tester) {
|
||||
return tester.firstRenderObject<RenderBox>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip),
|
||||
matching: find.byType(CustomPaint),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Material getMaterial(WidgetTester tester) {
|
||||
return tester.widget<Material>(
|
||||
find.descendant(
|
||||
of: find.byType(RawChip),
|
||||
matching: find.byType(Material),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
DefaultTextStyle getLabelStyle(WidgetTester tester, String labelText) {
|
||||
return tester.widget(
|
||||
find.ancestor(
|
||||
of: find.text(labelText),
|
||||
matching: find.byType(DefaultTextStyle),
|
||||
).first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Adds the basic requirements for a Chip.
|
||||
Widget wrapForChip({
|
||||
required Widget child,
|
||||
TextDirection textDirection = TextDirection.ltr,
|
||||
double textScaleFactor = 1.0,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(brightness: brightness),
|
||||
home: Directionality(
|
||||
textDirection: textDirection,
|
||||
child: MediaQuery(
|
||||
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
|
||||
child: Material(child: child),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
|
||||
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
|
||||
// There should be two Material widgets, first Material is from the "_wrapForChip" and
|
||||
// last Material is from the "RawChip".
|
||||
expect(materials.length, 2);
|
||||
// The last Material from `RawChip` should have the clip behavior.
|
||||
expect(materials.last.clipBehavior, clipBehavior);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('ChoiceChip defaults', (WidgetTester tester) async {
|
||||
Widget buildFrame(Brightness brightness) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(brightness: brightness),
|
||||
home: const Scaffold(
|
||||
body: Center(
|
||||
child: ChoiceChip(
|
||||
label: Text('Chip A'),
|
||||
selected: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildFrame(Brightness.light));
|
||||
expect(getMaterialBox(tester), paints..path(color: const Color(0x3d000000)));
|
||||
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
|
||||
expect(getMaterial(tester).color, null);
|
||||
expect(getMaterial(tester).elevation, 0);
|
||||
expect(getMaterial(tester).shape, const StadiumBorder());
|
||||
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xde000000);
|
||||
|
||||
await tester.pumpWidget(buildFrame(Brightness.dark));
|
||||
await tester.pumpAndSettle(); // Theme transition animation
|
||||
expect(getMaterialBox(tester), paints..path(color: const Color(0x3dffffff)));
|
||||
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
|
||||
expect(getMaterial(tester).color, null);
|
||||
expect(getMaterial(tester).elevation, 0);
|
||||
expect(getMaterial(tester).shape, const StadiumBorder());
|
||||
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xdeffffff);
|
||||
});
|
||||
|
||||
testWidgets('ChoiceChip can be tapped', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
child: ChoiceChip(
|
||||
selected: false,
|
||||
label: Text('choice chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(ChoiceChip));
|
||||
expect(tester.takeException(), null);
|
||||
});
|
||||
|
||||
testWidgets('ChoiceChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(wrapForChip(child: const ChoiceChip(label: label, selected: false)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(wrapForChip(child: const ChoiceChip(label: label, selected: false, clipBehavior: Clip.antiAlias)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
}
|
173
packages/flutter/test/material/chip_filter_test.dart
Normal file
173
packages/flutter/test/material/chip_filter_test.dart
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../rendering/mock_canvas.dart';
|
||||
|
||||
/// Adds the basic requirements for a Chip.
|
||||
Widget wrapForChip({
|
||||
required Widget child,
|
||||
TextDirection textDirection = TextDirection.ltr,
|
||||
double textScaleFactor = 1.0,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(brightness: brightness),
|
||||
home: Directionality(
|
||||
textDirection: textDirection,
|
||||
child: MediaQuery(
|
||||
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
|
||||
child: Material(child: child),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> pumpCheckmarkChip(
|
||||
WidgetTester tester, {
|
||||
required Widget chip,
|
||||
Color? themeColor,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) async {
|
||||
await tester.pumpWidget(
|
||||
wrapForChip(
|
||||
brightness: brightness,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final ChipThemeData chipTheme = ChipTheme.of(context);
|
||||
return ChipTheme(
|
||||
data: themeColor == null ? chipTheme : chipTheme.copyWith(
|
||||
checkmarkColor: themeColor,
|
||||
),
|
||||
child: chip,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget selectedFilterChip({ Color? checkmarkColor }) {
|
||||
return FilterChip(
|
||||
label: const Text('InputChip'),
|
||||
selected: true,
|
||||
showCheckmark: true,
|
||||
checkmarkColor: checkmarkColor,
|
||||
onSelected: (bool _) { },
|
||||
);
|
||||
}
|
||||
|
||||
void expectCheckmarkColor(Finder finder, Color color) {
|
||||
expect(
|
||||
finder,
|
||||
paints
|
||||
// The first path that is painted is the selection overlay. We do not care
|
||||
// how it is painted but it has to be added it to this pattern so that the
|
||||
// check mark can be checked next.
|
||||
..path()
|
||||
// The second path that is painted is the check mark.
|
||||
..path(color: color),
|
||||
);
|
||||
}
|
||||
|
||||
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
|
||||
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
|
||||
// There should be two Material widgets, first Material is from the "_wrapForChip" and
|
||||
// last Material is from the "RawChip".
|
||||
expect(materials.length, 2);
|
||||
// The last Material from `RawChip` should have the clip behavior.
|
||||
expect(materials.last.clipBehavior, clipBehavior);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('FilterChip can be tapped', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: FilterChip(
|
||||
onSelected: (bool valueChanged) { },
|
||||
label: const Text('filter chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(FilterChip));
|
||||
expect(tester.takeException(), null);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedFilterChip(),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
Colors.black.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedFilterChip(),
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
Colors.white.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color can be set by the chip theme', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedFilterChip(),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedFilterChip(checkmarkColor: const Color(0xff00ff00)),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedFilterChip(checkmarkColor: const Color(0xffff0000)),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
const Color(0xffff0000),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('FilterChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { })));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { }, clipBehavior: Clip.antiAlias)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
}
|
237
packages/flutter/test/material/chip_input_test.dart
Normal file
237
packages/flutter/test/material/chip_input_test.dart
Normal file
@ -0,0 +1,237 @@
|
||||
// Copyright 2014 The Flutter 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/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../rendering/mock_canvas.dart';
|
||||
|
||||
/// Adds the basic requirements for a Chip.
|
||||
Widget wrapForChip({
|
||||
required Widget child,
|
||||
TextDirection textDirection = TextDirection.ltr,
|
||||
double textScaleFactor = 1.0,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(brightness: brightness),
|
||||
home: Directionality(
|
||||
textDirection: textDirection,
|
||||
child: MediaQuery(
|
||||
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window).copyWith(textScaleFactor: textScaleFactor),
|
||||
child: Material(child: child),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget selectedInputChip({ Color? checkmarkColor }) {
|
||||
return InputChip(
|
||||
label: const Text('InputChip'),
|
||||
selected: true,
|
||||
showCheckmark: true,
|
||||
checkmarkColor: checkmarkColor,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Future<void> pumpCheckmarkChip(
|
||||
WidgetTester tester, {
|
||||
required Widget chip,
|
||||
Color? themeColor,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) async {
|
||||
await tester.pumpWidget(
|
||||
wrapForChip(
|
||||
brightness: brightness,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final ChipThemeData chipTheme = ChipTheme.of(context);
|
||||
return ChipTheme(
|
||||
data: themeColor == null ? chipTheme : chipTheme.copyWith(
|
||||
checkmarkColor: themeColor,
|
||||
),
|
||||
child: chip,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void expectCheckmarkColor(Finder finder, Color color) {
|
||||
expect(
|
||||
finder,
|
||||
paints
|
||||
// The first path that is painted is the selection overlay. We do not care
|
||||
// how it is painted but it has to be added it to this pattern so that the
|
||||
// check mark can be checked next.
|
||||
..path()
|
||||
// The second path that is painted is the check mark.
|
||||
..path(color: color),
|
||||
);
|
||||
}
|
||||
|
||||
void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) {
|
||||
final Iterable<Material> materials = tester.widgetList<Material>(find.byType(Material));
|
||||
// There should be two Material widgets, first Material is from the "_wrapForChip" and
|
||||
// last Material is from the "RawChip".
|
||||
expect(materials.length, 2);
|
||||
// The last Material from `RawChip` should have the clip behavior.
|
||||
expect(materials.last.clipBehavior, clipBehavior);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('InputChip can be tapped', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
child: InputChip(
|
||||
label: Text('input chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(InputChip));
|
||||
expect(tester.takeException(), null);
|
||||
});
|
||||
|
||||
testWidgets('loses focus when disabled', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'InputChip');
|
||||
await tester.pumpWidget(
|
||||
wrapForChip(
|
||||
child: InputChip(
|
||||
focusNode: focusNode,
|
||||
autofocus: true,
|
||||
shape: const RoundedRectangleBorder(),
|
||||
avatar: const CircleAvatar(child: Text('A')),
|
||||
label: const Text('Chip A'),
|
||||
onPressed: () { },
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrapForChip(
|
||||
child: InputChip(
|
||||
focusNode: focusNode,
|
||||
autofocus: true,
|
||||
shape: const RoundedRectangleBorder(),
|
||||
avatar: const CircleAvatar(child: Text('A')),
|
||||
label: const Text('Chip A'),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(focusNode.hasPrimaryFocus, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('cannot be traversed to when disabled', (WidgetTester tester) async {
|
||||
final FocusNode focusNode1 = FocusNode(debugLabel: 'InputChip 1');
|
||||
final FocusNode focusNode2 = FocusNode(debugLabel: 'InputChip 2');
|
||||
await tester.pumpWidget(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
InputChip(
|
||||
focusNode: focusNode1,
|
||||
autofocus: true,
|
||||
label: const Text('Chip A'),
|
||||
onPressed: () { },
|
||||
),
|
||||
InputChip(
|
||||
focusNode: focusNode2,
|
||||
autofocus: true,
|
||||
label: const Text('Chip B'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(focusNode1.hasPrimaryFocus, isTrue);
|
||||
expect(focusNode2.hasPrimaryFocus, isFalse);
|
||||
|
||||
expect(focusNode1.nextFocus(), isTrue);
|
||||
|
||||
await tester.pump();
|
||||
expect(focusNode1.hasPrimaryFocus, isTrue);
|
||||
expect(focusNode2.hasPrimaryFocus, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedInputChip(),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
Colors.black.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedInputChip(),
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
Colors.white.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color can be set by the chip theme', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedInputChip(),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedInputChip(checkmarkColor: const Color(0xff00ff00)),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
|
||||
await pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: selectedInputChip(checkmarkColor: const Color(0xffff0000)),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
const Color(0xffff0000),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('InputChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(wrapForChip(child: const InputChip(label: label)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(wrapForChip(child: const InputChip(label: label, clipBehavior: Clip.antiAlias)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
}
|
@ -71,7 +71,7 @@ double getDeleteDrawerProgress(WidgetTester tester) => getRenderChip(tester)?.de
|
||||
double getEnableProgress(WidgetTester tester) => getRenderChip(tester)?.enableAnimation?.value as double;
|
||||
|
||||
/// Adds the basic requirements for a Chip.
|
||||
Widget _wrapForChip({
|
||||
Widget wrapForChip({
|
||||
required Widget child,
|
||||
TextDirection textDirection = TextDirection.ltr,
|
||||
double textScaleFactor = 1.0,
|
||||
@ -93,7 +93,7 @@ Widget _wrapForChip({
|
||||
/// further constraining the size of its child, the label widget.
|
||||
/// Optionally, adding an avatar or delete icon to the chip should not
|
||||
/// cause the chip or label to exceed its constrained height.
|
||||
Future<void> _testConstrainedLabel(
|
||||
Future<void> testConstrainedLabel(
|
||||
WidgetTester tester, {
|
||||
CircleAvatar? avatar,
|
||||
VoidCallback? onDeleted,
|
||||
@ -105,7 +105,7 @@ Future<void> _testConstrainedLabel(
|
||||
final Key labelKey = UniqueKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: chipParentWidth,
|
||||
@ -133,65 +133,9 @@ Future<void> _testConstrainedLabel(
|
||||
expect(chipSize.height, chipParentHeight);
|
||||
}
|
||||
|
||||
Widget _selectedInputChip({ Color? checkmarkColor }) {
|
||||
return InputChip(
|
||||
label: const Text('InputChip'),
|
||||
selected: true,
|
||||
showCheckmark: true,
|
||||
checkmarkColor: checkmarkColor,
|
||||
);
|
||||
}
|
||||
void doNothing() {}
|
||||
|
||||
Widget _selectedFilterChip({ Color? checkmarkColor }) {
|
||||
return FilterChip(
|
||||
label: const Text('InputChip'),
|
||||
selected: true,
|
||||
showCheckmark: true,
|
||||
checkmarkColor: checkmarkColor,
|
||||
onSelected: (bool _) { },
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _pumpCheckmarkChip(
|
||||
WidgetTester tester, {
|
||||
required Widget chip,
|
||||
Color? themeColor,
|
||||
Brightness brightness = Brightness.light,
|
||||
}) async {
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
brightness: brightness,
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
final ChipThemeData chipTheme = ChipTheme.of(context);
|
||||
return ChipTheme(
|
||||
data: themeColor == null ? chipTheme : chipTheme.copyWith(
|
||||
checkmarkColor: themeColor,
|
||||
),
|
||||
child: chip,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _expectCheckmarkColor(Finder finder, Color color) {
|
||||
expect(
|
||||
finder,
|
||||
paints
|
||||
// The first path that is painted is the selection overlay. We do not care
|
||||
// how it is painted but it has to be added it to this pattern so that the
|
||||
// check mark can be checked next.
|
||||
..path()
|
||||
// The second path that is painted is the check mark.
|
||||
..path(color: color),
|
||||
);
|
||||
}
|
||||
|
||||
void _doNothing() {}
|
||||
|
||||
Widget _chipWithOptionalDeleteButton({
|
||||
Widget chipWithOptionalDeleteButton({
|
||||
Key? deleteButtonKey,
|
||||
Key? labelKey,
|
||||
required bool deletable,
|
||||
@ -199,16 +143,16 @@ Widget _chipWithOptionalDeleteButton({
|
||||
bool useDeleteButtonTooltip = true,
|
||||
String? chipTooltip,
|
||||
String? deleteButtonTooltipMessage,
|
||||
VoidCallback? onPressed = _doNothing,
|
||||
VoidCallback? onPressed = doNothing,
|
||||
}) {
|
||||
return _wrapForChip(
|
||||
return wrapForChip(
|
||||
textDirection: textDirection,
|
||||
child: Wrap(
|
||||
children: <Widget>[
|
||||
RawChip(
|
||||
tooltip: chipTooltip,
|
||||
onPressed: onPressed,
|
||||
onDeleted: deletable ? _doNothing : null,
|
||||
onDeleted: deletable ? doNothing : null,
|
||||
deleteIcon: Icon(Icons.close, key: deleteButtonKey),
|
||||
useDeleteButtonTooltip: useDeleteButtonTooltip,
|
||||
deleteButtonTooltipMessage: deleteButtonTooltipMessage,
|
||||
@ -347,44 +291,11 @@ void main() {
|
||||
expect(labelStyle.wordSpacing, textTheme.bodyText1?.wordSpacing);
|
||||
});
|
||||
|
||||
testWidgets('ChoiceChip defaults', (WidgetTester tester) async {
|
||||
Widget buildFrame(Brightness brightness) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(brightness: brightness),
|
||||
home: const Scaffold(
|
||||
body: Center(
|
||||
child: ChoiceChip(
|
||||
label: Text('Chip A'),
|
||||
selected: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildFrame(Brightness.light));
|
||||
expect(getMaterialBox(tester), paints..path(color: const Color(0x3d000000)));
|
||||
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
|
||||
expect(getMaterial(tester).color, null);
|
||||
expect(getMaterial(tester).elevation, 0);
|
||||
expect(getMaterial(tester).shape, const StadiumBorder());
|
||||
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xde000000);
|
||||
|
||||
await tester.pumpWidget(buildFrame(Brightness.dark));
|
||||
await tester.pumpAndSettle(); // Theme transition animation
|
||||
expect(getMaterialBox(tester), paints..path(color: const Color(0x3dffffff)));
|
||||
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
|
||||
expect(getMaterial(tester).color, null);
|
||||
expect(getMaterial(tester).elevation, 0);
|
||||
expect(getMaterial(tester).shape, const StadiumBorder());
|
||||
expect(getLabelStyle(tester, 'Chip A').style.color?.value, 0xdeffffff);
|
||||
});
|
||||
|
||||
testWidgets('Chip control test', (WidgetTester tester) async {
|
||||
final FeedbackTester feedback = FeedbackTester();
|
||||
final List<String> deletedChipLabels = <String>[];
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Chip(
|
||||
@ -438,7 +349,7 @@ void main() {
|
||||
final Key labelKey = UniqueKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 500.0,
|
||||
@ -469,7 +380,7 @@ void main() {
|
||||
'Chip constrains the size of the label widget when it exceeds the '
|
||||
'available space',
|
||||
(WidgetTester tester) async {
|
||||
await _testConstrainedLabel(tester);
|
||||
await testConstrainedLabel(tester);
|
||||
},
|
||||
);
|
||||
|
||||
@ -477,7 +388,7 @@ void main() {
|
||||
'Chip constrains the size of the label widget when it exceeds the '
|
||||
'available space and the avatar is present',
|
||||
(WidgetTester tester) async {
|
||||
await _testConstrainedLabel(
|
||||
await testConstrainedLabel(
|
||||
tester,
|
||||
avatar: const CircleAvatar(child: Text('A')),
|
||||
);
|
||||
@ -488,7 +399,7 @@ void main() {
|
||||
'Chip constrains the size of the label widget when it exceeds the '
|
||||
'available space and the delete icon is present',
|
||||
(WidgetTester tester) async {
|
||||
await _testConstrainedLabel(
|
||||
await testConstrainedLabel(
|
||||
tester,
|
||||
onDeleted: () { },
|
||||
);
|
||||
@ -499,7 +410,7 @@ void main() {
|
||||
'Chip constrains the size of the label widget when it exceeds the '
|
||||
'available space and both avatar and delete icons are present',
|
||||
(WidgetTester tester) async {
|
||||
await _testConstrainedLabel(
|
||||
await testConstrainedLabel(
|
||||
tester,
|
||||
avatar: const CircleAvatar(child: Text('A')),
|
||||
onDeleted: () { },
|
||||
@ -585,7 +496,7 @@ void main() {
|
||||
testWidgets('Chip in row works ok', (WidgetTester tester) async {
|
||||
const TextStyle style = TextStyle(fontFamily: 'Ahem', fontSize: 10.0);
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Row(
|
||||
children: const <Widget>[
|
||||
Chip(label: Text('Test'), labelStyle: style),
|
||||
@ -596,7 +507,7 @@ void main() {
|
||||
expect(tester.getSize(find.byType(Text)), const Size(40.0, 10.0));
|
||||
expect(tester.getSize(find.byType(Chip)), const Size(64.0, 48.0));
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Row(
|
||||
children: const <Widget>[
|
||||
Flexible(child: Chip(label: Text('Test'), labelStyle: style)),
|
||||
@ -607,7 +518,7 @@ void main() {
|
||||
expect(tester.getSize(find.byType(Text)), const Size(40.0, 10.0));
|
||||
expect(tester.getSize(find.byType(Chip)), const Size(64.0, 48.0));
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Row(
|
||||
children: const <Widget>[
|
||||
Expanded(child: Chip(label: Text('Test'), labelStyle: style)),
|
||||
@ -621,7 +532,7 @@ void main() {
|
||||
|
||||
testWidgets('Chip responds to materialTapTargetSize', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: const <Widget>[
|
||||
Chip(
|
||||
@ -645,7 +556,7 @@ void main() {
|
||||
final UniqueKey deleteKey = UniqueKey();
|
||||
bool calledDelete = false;
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Chip(
|
||||
@ -670,7 +581,7 @@ void main() {
|
||||
calledDelete = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Chip(
|
||||
@ -719,7 +630,7 @@ void main() {
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: test,
|
||||
textDirection: TextDirection.rtl,
|
||||
),
|
||||
@ -727,7 +638,7 @@ void main() {
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(tester.getCenter(find.text('ABC')).dx, greaterThan(tester.getCenter(find.byKey(iconKey)).dx));
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: test,
|
||||
),
|
||||
);
|
||||
@ -737,7 +648,7 @@ void main() {
|
||||
|
||||
testWidgets('Chip responds to textScaleFactor', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: const <Widget>[
|
||||
Chip(
|
||||
@ -767,7 +678,7 @@ void main() {
|
||||
expect(tester.getSize(find.byType(Chip).last), anyOf(const Size(132.0, 48.0), const Size(131.0, 48.0)));
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
textScaleFactor: 3.0,
|
||||
child: Column(
|
||||
children: const <Widget>[
|
||||
@ -795,7 +706,7 @@ void main() {
|
||||
|
||||
// Check that individual text scales are taken into account.
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: const <Widget>[
|
||||
Chip(
|
||||
@ -824,7 +735,7 @@ void main() {
|
||||
final Key keyA = GlobalKey();
|
||||
final Key keyB = GlobalKey();
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Chip(
|
||||
@ -857,7 +768,7 @@ void main() {
|
||||
testWidgets('Avatars can be non-circle avatar widgets', (WidgetTester tester) async {
|
||||
final Key keyA = GlobalKey();
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Chip(
|
||||
@ -875,7 +786,7 @@ void main() {
|
||||
testWidgets('Delete icons can be non-icon widgets', (WidgetTester tester) async {
|
||||
final Key keyA = GlobalKey();
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Chip(
|
||||
@ -895,7 +806,7 @@ void main() {
|
||||
final GlobalKey keyA = GlobalKey();
|
||||
final GlobalKey keyB = GlobalKey();
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
OverlayEntry(
|
||||
@ -931,7 +842,7 @@ void main() {
|
||||
final GlobalKey keyA = GlobalKey();
|
||||
final GlobalKey keyB = GlobalKey();
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Overlay(
|
||||
initialEntries: <OverlayEntry>[
|
||||
@ -969,7 +880,7 @@ void main() {
|
||||
final GlobalKey labelKey = GlobalKey();
|
||||
Future<void> pushChip({ Widget? avatar }) async {
|
||||
return tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Wrap(
|
||||
children: <Widget>[
|
||||
RawChip(
|
||||
@ -1083,7 +994,7 @@ void main() {
|
||||
bool wasDeleted = false;
|
||||
Future<void> pushChip({ bool deletable = false }) async {
|
||||
return tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Wrap(
|
||||
children: <Widget>[
|
||||
StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
@ -1199,7 +1110,7 @@ void main() {
|
||||
bool deletePressed = false;
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Wrap(
|
||||
children: <Widget>[
|
||||
RawChip(
|
||||
@ -1234,7 +1145,7 @@ void main() {
|
||||
final UniqueKey deleteButtonKey = UniqueKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
labelKey: labelKey,
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
deletable: true,
|
||||
@ -1283,7 +1194,7 @@ void main() {
|
||||
final GlobalKey deleteButtonKey = GlobalKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
labelKey: labelKey,
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
deletable: true,
|
||||
@ -1316,7 +1227,7 @@ void main() {
|
||||
final UniqueKey deleteButtonKey = UniqueKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
labelKey: labelKey,
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
deletable: true,
|
||||
@ -1369,7 +1280,7 @@ void main() {
|
||||
final UniqueKey deleteButtonKey = UniqueKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
labelKey: labelKey,
|
||||
onPressed: null,
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
@ -1424,7 +1335,7 @@ void main() {
|
||||
final UniqueKey deleteButtonKey = UniqueKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
labelKey: labelKey,
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
deletable: true,
|
||||
@ -1453,7 +1364,7 @@ void main() {
|
||||
final UniqueKey labelKey = UniqueKey();
|
||||
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
labelKey: labelKey,
|
||||
deletable: false,
|
||||
),
|
||||
@ -1507,7 +1418,7 @@ void main() {
|
||||
final UniqueKey labelKey = UniqueKey();
|
||||
Future<void> pushChip({ Widget? avatar, bool selectable = false }) async {
|
||||
return tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Wrap(
|
||||
children: <Widget>[
|
||||
StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
@ -1587,7 +1498,7 @@ void main() {
|
||||
final UniqueKey labelKey = UniqueKey();
|
||||
Future<void> pushChip({ bool selectable = false }) async {
|
||||
return tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Wrap(
|
||||
children: <Widget>[
|
||||
StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
@ -1660,7 +1571,7 @@ void main() {
|
||||
final UniqueKey labelKey = UniqueKey();
|
||||
Future<void> pushChip({ Widget? avatar, bool selectable = false }) async {
|
||||
return tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Wrap(
|
||||
children: <Widget>[
|
||||
StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
@ -1719,7 +1630,7 @@ void main() {
|
||||
final ChipThemeData chipTheme = theme.chipTheme;
|
||||
|
||||
Widget buildChip(ChipThemeData data) {
|
||||
return _wrapForChip(
|
||||
return wrapForChip(
|
||||
child: Theme(
|
||||
data: theme,
|
||||
child: const InputChip(
|
||||
@ -1748,7 +1659,7 @@ void main() {
|
||||
);
|
||||
|
||||
Widget buildChip() {
|
||||
return _wrapForChip(
|
||||
return wrapForChip(
|
||||
child: Theme(
|
||||
data: theme,
|
||||
child: const Chip(
|
||||
@ -1769,7 +1680,7 @@ void main() {
|
||||
|
||||
testWidgets('ChipTheme labelStyle with inherit:true', (WidgetTester tester) async {
|
||||
Widget buildChip() {
|
||||
return _wrapForChip(
|
||||
return wrapForChip(
|
||||
child: Theme(
|
||||
data: ThemeData.light().copyWith(
|
||||
chipTheme: const ChipThemeData(
|
||||
@ -1789,7 +1700,7 @@ void main() {
|
||||
|
||||
testWidgets('Chip does not merge inherit:false label style with the theme label style', (WidgetTester tester) async {
|
||||
Widget buildChip() {
|
||||
return _wrapForChip(
|
||||
return wrapForChip(
|
||||
child: Theme(
|
||||
data: ThemeData(fontFamily: 'MyFont'),
|
||||
child: const DefaultTextStyle(
|
||||
@ -1814,7 +1725,7 @@ void main() {
|
||||
testWidgets('Chip size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async {
|
||||
final Key key1 = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Theme(
|
||||
data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded),
|
||||
child: Center(
|
||||
@ -1831,7 +1742,7 @@ void main() {
|
||||
|
||||
final Key key2 = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Theme(
|
||||
data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap),
|
||||
child: Center(
|
||||
@ -1868,7 +1779,7 @@ void main() {
|
||||
bool showCheckmark = true,
|
||||
}) {
|
||||
chipTheme ??= defaultChipTheme;
|
||||
return _wrapForChip(
|
||||
return wrapForChip(
|
||||
child: Theme(
|
||||
data: themeData,
|
||||
child: ChipTheme(
|
||||
@ -2450,7 +2361,7 @@ void main() {
|
||||
testWidgets('can be tapped outside of chip delete icon', (WidgetTester tester) async {
|
||||
bool deleted = false;
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Chip(
|
||||
@ -2474,20 +2385,6 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('Chips can be tapped', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
child: ChoiceChip(
|
||||
selected: false,
|
||||
label: Text('choice chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(ChoiceChip));
|
||||
expect(tester.takeException(), null);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
@ -2500,47 +2397,6 @@ void main() {
|
||||
|
||||
await tester.tap(find.byType(RawChip));
|
||||
expect(tester.takeException(), null);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: ActionChip(
|
||||
onPressed: () { },
|
||||
label: const Text('action chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(ActionChip));
|
||||
expect(tester.takeException(), null);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: FilterChip(
|
||||
onSelected: (bool valueChanged) { },
|
||||
label: const Text('filter chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(FilterChip));
|
||||
expect(tester.takeException(), null);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
child: InputChip(
|
||||
label: Text('input chip'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(InputChip));
|
||||
expect(tester.takeException(), null);
|
||||
});
|
||||
|
||||
testWidgets('Chip elevation and shadow color work correctly', (WidgetTester tester) async {
|
||||
@ -2554,7 +2410,7 @@ void main() {
|
||||
InputChip inputChip = const InputChip(label: Text('Label'));
|
||||
|
||||
Widget buildChip(ChipThemeData data) {
|
||||
return _wrapForChip(
|
||||
return wrapForChip(
|
||||
child: Theme(
|
||||
data: theme,
|
||||
child: inputChip,
|
||||
@ -2596,7 +2452,7 @@ void main() {
|
||||
testWidgets('can be tapped outside of chip body', (WidgetTester tester) async {
|
||||
bool pressed = false;
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
InputChip(
|
||||
@ -2620,7 +2476,7 @@ void main() {
|
||||
|
||||
testWidgets('is hitTestable', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
wrapForChip(
|
||||
child: InputChip(
|
||||
shape: const RoundedRectangleBorder(),
|
||||
avatar: const CircleAvatar(child: Text('A')),
|
||||
@ -2641,51 +2497,15 @@ void main() {
|
||||
|
||||
testWidgets('Chip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(_wrapForChip(child: const Chip(label: label)));
|
||||
await tester.pumpWidget(wrapForChip(child: const Chip(label: label)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(_wrapForChip(child: const Chip(label: label, clipBehavior: Clip.antiAlias)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
|
||||
testWidgets('ChoiceChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(_wrapForChip(child: const ChoiceChip(label: label, selected: false)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(_wrapForChip(child: const ChoiceChip(label: label, selected: false, clipBehavior: Clip.antiAlias)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
|
||||
testWidgets('FilterChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(_wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { })));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(_wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { }, clipBehavior: Clip.antiAlias)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
|
||||
testWidgets('ActionChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(_wrapForChip(child: ActionChip(label: label, onPressed: () { })));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(_wrapForChip(child: ActionChip(label: label, clipBehavior: Clip.antiAlias, onPressed: () { })));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
|
||||
testWidgets('InputChip clipBehavior properly passes through to the Material', (WidgetTester tester) async {
|
||||
const Text label = Text('label');
|
||||
await tester.pumpWidget(_wrapForChip(child: const InputChip(label: label)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.none);
|
||||
|
||||
await tester.pumpWidget(_wrapForChip(child: const InputChip(label: label, clipBehavior: Clip.antiAlias)));
|
||||
await tester.pumpWidget(wrapForChip(child: const Chip(label: label, clipBehavior: Clip.antiAlias)));
|
||||
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
|
||||
});
|
||||
|
||||
testWidgets('selected chip and avatar draw darkened layer within avatar circle', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(_wrapForChip(child: const FilterChip(
|
||||
await tester.pumpWidget(wrapForChip(child: const FilterChip(
|
||||
avatar: CircleAvatar(child: Text('t')),
|
||||
label: Text('test'),
|
||||
selected: true,
|
||||
@ -3198,71 +3018,6 @@ void main() {
|
||||
expect(find.byType(RawChip), paints..drrect(color: selectedBorderSide.color));
|
||||
});
|
||||
|
||||
testWidgets('loses focus when disabled', (WidgetTester tester) async {
|
||||
final FocusNode focusNode = FocusNode(debugLabel: 'InputChip');
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
child: InputChip(
|
||||
focusNode: focusNode,
|
||||
autofocus: true,
|
||||
shape: const RoundedRectangleBorder(),
|
||||
avatar: const CircleAvatar(child: Text('A')),
|
||||
label: const Text('Chip A'),
|
||||
onPressed: () { },
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(focusNode.hasPrimaryFocus, isTrue);
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
child: InputChip(
|
||||
focusNode: focusNode,
|
||||
autofocus: true,
|
||||
shape: const RoundedRectangleBorder(),
|
||||
avatar: const CircleAvatar(child: Text('A')),
|
||||
label: const Text('Chip A'),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(focusNode.hasPrimaryFocus, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('cannot be traversed to when disabled', (WidgetTester tester) async {
|
||||
final FocusNode focusNode1 = FocusNode(debugLabel: 'InputChip 1');
|
||||
final FocusNode focusNode2 = FocusNode(debugLabel: 'InputChip 2');
|
||||
await tester.pumpWidget(
|
||||
_wrapForChip(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
InputChip(
|
||||
focusNode: focusNode1,
|
||||
autofocus: true,
|
||||
label: const Text('Chip A'),
|
||||
onPressed: () { },
|
||||
),
|
||||
InputChip(
|
||||
focusNode: focusNode2,
|
||||
autofocus: true,
|
||||
label: const Text('Chip B'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(focusNode1.hasPrimaryFocus, isTrue);
|
||||
expect(focusNode2.hasPrimaryFocus, isFalse);
|
||||
|
||||
expect(focusNode1.nextFocus(), isTrue);
|
||||
|
||||
await tester.pump();
|
||||
expect(focusNode1.hasPrimaryFocus, isTrue);
|
||||
expect(focusNode2.hasPrimaryFocus, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('Chip responds to density changes.', (WidgetTester tester) async {
|
||||
const Key key = Key('test');
|
||||
const Key textKey = Key('test text');
|
||||
@ -3368,135 +3123,9 @@ void main() {
|
||||
expect(box.size, equals(const Size(128, 24.0 + 16.0)));
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedInputChip(),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
Colors.black.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color is determined by platform brightness when light', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedFilterChip(),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
Colors.black.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedInputChip(),
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
Colors.white.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedFilterChip(),
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
Colors.white.withAlpha(0xde),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color can be set by the chip theme', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedInputChip(),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color can be set by the chip theme', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedFilterChip(),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedInputChip(checkmarkColor: const Color(0xff00ff00)),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color can be set by the chip constructor', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedFilterChip(checkmarkColor: const Color(0xff00ff00)),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
const Color(0xff00ff00),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Input chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedInputChip(checkmarkColor: const Color(0xffff0000)),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(InputChip),
|
||||
const Color(0xffff0000),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Filter chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async {
|
||||
await _pumpCheckmarkChip(
|
||||
tester,
|
||||
chip: _selectedFilterChip(checkmarkColor: const Color(0xffff0000)),
|
||||
themeColor: const Color(0xff00ff00),
|
||||
);
|
||||
|
||||
_expectCheckmarkColor(
|
||||
find.byType(FilterChip),
|
||||
const Color(0xffff0000),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Chip delete button tooltip can be disabled using useDeleteButtonTooltip', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
deletable: true,
|
||||
useDeleteButtonTooltip: false,
|
||||
),
|
||||
@ -3522,7 +3151,7 @@ void main() {
|
||||
testWidgets('Chip delete button tooltip is disabled if deleteButtonTooltipMessage is empty', (WidgetTester tester) async {
|
||||
final UniqueKey deleteButtonKey = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
deletable: true,
|
||||
deleteButtonTooltipMessage: '',
|
||||
@ -3547,7 +3176,7 @@ void main() {
|
||||
testWidgets('Disabling delete button tooltip does not disable chip tooltip', (WidgetTester tester) async {
|
||||
final UniqueKey deleteButtonKey = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
deletable: true,
|
||||
deleteButtonTooltipMessage: '',
|
||||
@ -3575,7 +3204,7 @@ void main() {
|
||||
testWidgets('Triggering delete button tooltip does not trigger Chip tooltip', (WidgetTester tester) async {
|
||||
final UniqueKey deleteButtonKey = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
_chipWithOptionalDeleteButton(
|
||||
chipWithOptionalDeleteButton(
|
||||
deleteButtonKey: deleteButtonKey,
|
||||
deletable: true,
|
||||
chipTooltip: 'Chip Tooltip',
|
||||
@ -3601,7 +3230,7 @@ void main() {
|
||||
|
||||
testWidgets('intrinsicHeight implementation meets constraints', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/49478.
|
||||
await tester.pumpWidget(_wrapForChip(
|
||||
await tester.pumpWidget(wrapForChip(
|
||||
child: const Chip(
|
||||
label: Text('text'),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
|
Loading…
x
Reference in New Issue
Block a user