Unverified Commit e57f57c7 authored by rami-a's avatar rami-a Committed by GitHub

Add elevation to Chips to allow for more flexibility (#27316)

Expose elevation on chips and allow for it to be customized by the developer.
parent fac051c7
...@@ -111,6 +111,13 @@ abstract class ChipAttributes { ...@@ -111,6 +111,13 @@ abstract class ChipAttributes {
/// ///
/// * [MaterialTapTargetSize], for a description of how this affects tap targets. /// * [MaterialTapTargetSize], for a description of how this affects tap targets.
MaterialTapTargetSize get materialTapTargetSize; MaterialTapTargetSize get materialTapTargetSize;
/// Elevation to be applied on the chip relative to its parent.
///
/// This controls the size of the shadow below the chip.
///
/// Defaults to 0. The value is always non-negative.
double get elevation;
} }
/// An interface for material design chips that can be deleted. /// An interface for material design chips that can be deleted.
...@@ -460,7 +467,8 @@ abstract class TappableChipAttributes { ...@@ -460,7 +467,8 @@ abstract class TappableChipAttributes {
class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttributes { class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttributes {
/// Creates a material design chip. /// Creates a material design chip.
/// ///
/// The [label] and [clipBehavior] arguments must not be null. /// The [label], [elevation], and [clipBehavior] arguments must not be null.
/// Additionally, the [elevation] must be non-negative.
const Chip({ const Chip({
Key key, Key key,
this.avatar, this.avatar,
...@@ -476,8 +484,10 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri ...@@ -476,8 +484,10 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
this.backgroundColor, this.backgroundColor,
this.padding, this.padding,
this.materialTapTargetSize, this.materialTapTargetSize,
this.elevation = 0.0,
}) : assert(label != null), }) : assert(label != null),
assert(clipBehavior != null), assert(clipBehavior != null),
assert(elevation != null && elevation >= 0.0),
super(key: key); super(key: key);
@override @override
...@@ -506,6 +516,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri ...@@ -506,6 +516,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
final String deleteButtonTooltipMessage; final String deleteButtonTooltipMessage;
@override @override
final MaterialTapTargetSize materialTapTargetSize; final MaterialTapTargetSize materialTapTargetSize;
@override
final double elevation;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -525,6 +537,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri ...@@ -525,6 +537,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
padding: padding, padding: padding,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
isEnabled: true, isEnabled: true,
); );
} }
...@@ -587,8 +600,10 @@ class InputChip extends StatelessWidget ...@@ -587,8 +600,10 @@ class InputChip extends StatelessWidget
/// The [onPressed] and [onSelected] callbacks must not both be specified at /// The [onPressed] and [onSelected] callbacks must not both be specified at
/// the same time. /// the same time.
/// ///
/// The [label], [isEnabled], [selected], and [clipBehavior] arguments must /// The [label], [isEnabled], [selected], [pressElevation], [elevation] and
/// not be null. /// [clipBehavior] arguments must not be null. Additionally, [pressElevation]
/// and [elevation] must be non-negative. Typically, [pressElevation] is
/// greater than [elevation].
const InputChip({ const InputChip({
Key key, Key key,
this.avatar, this.avatar,
...@@ -612,11 +627,14 @@ class InputChip extends StatelessWidget ...@@ -612,11 +627,14 @@ class InputChip extends StatelessWidget
this.backgroundColor, this.backgroundColor,
this.padding, this.padding,
this.materialTapTargetSize, this.materialTapTargetSize,
this.elevation = 0.0,
this.avatarBorder = const CircleBorder(), this.avatarBorder = const CircleBorder(),
}) : assert(selected != null), }) : assert(selected != null),
assert(isEnabled != null), assert(isEnabled != null),
assert(label != null), assert(label != null),
assert(clipBehavior != null), assert(clipBehavior != null),
assert(pressElevation != null && pressElevation >= 0.0),
assert(elevation != null && elevation >= 0.0),
super(key: key); super(key: key);
@override @override
...@@ -662,6 +680,8 @@ class InputChip extends StatelessWidget ...@@ -662,6 +680,8 @@ class InputChip extends StatelessWidget
@override @override
final MaterialTapTargetSize materialTapTargetSize; final MaterialTapTargetSize materialTapTargetSize;
@override @override
final double elevation;
@override
final ShapeBorder avatarBorder; final ShapeBorder avatarBorder;
@override @override
...@@ -689,6 +709,7 @@ class InputChip extends StatelessWidget ...@@ -689,6 +709,7 @@ class InputChip extends StatelessWidget
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
padding: padding, padding: padding,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null), isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null),
avatarBorder: avatarBorder, avatarBorder: avatarBorder,
); );
...@@ -756,7 +777,10 @@ class ChoiceChip extends StatelessWidget ...@@ -756,7 +777,10 @@ class ChoiceChip extends StatelessWidget
DisabledChipAttributes { DisabledChipAttributes {
/// Create a chip that acts like a radio button. /// Create a chip that acts like a radio button.
/// ///
/// The [label], [selected], and [clipBehavior] attributes must not be null. /// The [label], [selected], [pressElevation], [elevation] and [clipBehavior]
/// arguments must not be null. Additionally, [pressElevation] and [elevation]
/// must be non-negative. Typically, [pressElevation] is greater than
/// [elevation].
const ChoiceChip({ const ChoiceChip({
Key key, Key key,
this.avatar, this.avatar,
...@@ -774,10 +798,13 @@ class ChoiceChip extends StatelessWidget ...@@ -774,10 +798,13 @@ class ChoiceChip extends StatelessWidget
this.backgroundColor, this.backgroundColor,
this.padding, this.padding,
this.materialTapTargetSize, this.materialTapTargetSize,
this.elevation = 0.0,
this.avatarBorder = const CircleBorder(), this.avatarBorder = const CircleBorder(),
}) : assert(selected != null), }) : assert(selected != null),
assert(label != null), assert(label != null),
assert(clipBehavior != null), assert(clipBehavior != null),
assert(pressElevation != null && pressElevation >= 0.0),
assert(elevation != null && elevation >= 0.0),
super(key: key); super(key: key);
@override @override
...@@ -811,6 +838,8 @@ class ChoiceChip extends StatelessWidget ...@@ -811,6 +838,8 @@ class ChoiceChip extends StatelessWidget
@override @override
final MaterialTapTargetSize materialTapTargetSize; final MaterialTapTargetSize materialTapTargetSize;
@override @override
final double elevation;
@override
final ShapeBorder avatarBorder; final ShapeBorder avatarBorder;
@override @override
...@@ -839,6 +868,7 @@ class ChoiceChip extends StatelessWidget ...@@ -839,6 +868,7 @@ class ChoiceChip extends StatelessWidget
padding: padding, padding: padding,
isEnabled: isEnabled, isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
avatarBorder: avatarBorder, avatarBorder: avatarBorder,
); );
} }
...@@ -937,7 +967,10 @@ class FilterChip extends StatelessWidget ...@@ -937,7 +967,10 @@ class FilterChip extends StatelessWidget
DisabledChipAttributes { DisabledChipAttributes {
/// Create a chip that acts like a checkbox. /// Create a chip that acts like a checkbox.
/// ///
/// The [selected] and [label] attributes must not be null. /// The [selected], [label], [pressElevation], [elevation] and [clipBehavior]
/// arguments must not be null. Additionally, [pressElevation] and [elevation]
/// must be non-negative. Typically, [pressElevation] is greater than
/// [elevation].
const FilterChip({ const FilterChip({
Key key, Key key,
this.avatar, this.avatar,
...@@ -955,10 +988,13 @@ class FilterChip extends StatelessWidget ...@@ -955,10 +988,13 @@ class FilterChip extends StatelessWidget
this.backgroundColor, this.backgroundColor,
this.padding, this.padding,
this.materialTapTargetSize, this.materialTapTargetSize,
this.elevation = 0.0,
this.avatarBorder = const CircleBorder(), this.avatarBorder = const CircleBorder(),
}) : assert(selected != null), }) : assert(selected != null),
assert(label != null), assert(label != null),
assert(clipBehavior != null), assert(clipBehavior != null),
assert(pressElevation != null && pressElevation >= 0.0),
assert(elevation != null && elevation >= 0.0),
super(key: key); super(key: key);
@override @override
...@@ -992,6 +1028,8 @@ class FilterChip extends StatelessWidget ...@@ -992,6 +1028,8 @@ class FilterChip extends StatelessWidget
@override @override
final MaterialTapTargetSize materialTapTargetSize; final MaterialTapTargetSize materialTapTargetSize;
@override @override
final double elevation;
@override
final ShapeBorder avatarBorder; final ShapeBorder avatarBorder;
@override @override
...@@ -1017,6 +1055,7 @@ class FilterChip extends StatelessWidget ...@@ -1017,6 +1055,7 @@ class FilterChip extends StatelessWidget
padding: padding, padding: padding,
isEnabled: isEnabled, isEnabled: isEnabled,
materialTapTargetSize: materialTapTargetSize, materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
avatarBorder: avatarBorder, avatarBorder: avatarBorder,
); );
} }
...@@ -1072,7 +1111,10 @@ class FilterChip extends StatelessWidget ...@@ -1072,7 +1111,10 @@ class FilterChip extends StatelessWidget
class ActionChip extends StatelessWidget implements ChipAttributes, TappableChipAttributes { class ActionChip extends StatelessWidget implements ChipAttributes, TappableChipAttributes {
/// Create a chip that acts like a button. /// Create a chip that acts like a button.
/// ///
/// The [label], [onPressed], and [clipBehavior] arguments must not be null. /// The [label], [onPressed], [pressElevation], [elevation] and [clipBehavior]
/// arguments must not be null. Additionally, [pressElevation] and [elevation]
/// must be non-negative. Typically, [pressElevation] is greater than
/// [elevation].
const ActionChip({ const ActionChip({
Key key, Key key,
this.avatar, this.avatar,
...@@ -1087,12 +1129,15 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip ...@@ -1087,12 +1129,15 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
this.backgroundColor, this.backgroundColor,
this.padding, this.padding,
this.materialTapTargetSize, this.materialTapTargetSize,
this.elevation = 0.0,
}) : assert(label != null), }) : assert(label != null),
assert( assert(
onPressed != null, onPressed != null,
'Rather than disabling an ActionChip by setting onPressed to null, ' 'Rather than disabling an ActionChip by setting onPressed to null, '
'remove it from the interface entirely.', 'remove it from the interface entirely.',
), ),
assert(pressElevation != null && pressElevation >= 0.0),
assert(elevation != null && elevation >= 0.0),
super(key: key); super(key: key);
@override @override
...@@ -1119,6 +1164,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip ...@@ -1119,6 +1164,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
@override @override
final MaterialTapTargetSize materialTapTargetSize; final MaterialTapTargetSize materialTapTargetSize;
@override
final double elevation;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -1136,7 +1183,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip ...@@ -1136,7 +1183,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
padding: padding, padding: padding,
labelPadding: labelPadding, labelPadding: labelPadding,
isEnabled: true, isEnabled: true,
materialTapTargetSize: materialTapTargetSize materialTapTargetSize: materialTapTargetSize,
elevation: elevation,
); );
} }
} }
...@@ -1183,8 +1231,10 @@ class RawChip extends StatefulWidget ...@@ -1183,8 +1231,10 @@ class RawChip extends StatefulWidget
/// The [onPressed] and [onSelected] callbacks must not both be specified at /// The [onPressed] and [onSelected] callbacks must not both be specified at
/// the same time. /// the same time.
/// ///
/// The [label], [pressElevation], [isEnabled], and [clipBehavior] arguments /// The [label], [pressElevation], [elevation], [isEnabled], and
/// must not be null. Additionally, [pressElevation] must be non-negative. /// [clipBehavior] arguments must not be null. Additionally, [pressElevation]
/// and [elevation] must be non-negative. Typically, [pressElevation] is
/// greater than [elevation].
const RawChip({ const RawChip({
Key key, Key key,
this.avatar, this.avatar,
...@@ -1210,11 +1260,13 @@ class RawChip extends StatefulWidget ...@@ -1210,11 +1260,13 @@ class RawChip extends StatefulWidget
this.clipBehavior = Clip.none, this.clipBehavior = Clip.none,
this.backgroundColor, this.backgroundColor,
this.materialTapTargetSize, this.materialTapTargetSize,
this.elevation = 0.0,
this.avatarBorder = const CircleBorder(), this.avatarBorder = const CircleBorder(),
}) : assert(label != null), }) : assert(label != null),
assert(isEnabled != null), assert(isEnabled != null),
assert(clipBehavior != null), assert(clipBehavior != null),
assert(pressElevation != null && pressElevation >= 0.0), assert(pressElevation != null && pressElevation >= 0.0),
assert(elevation != null && elevation >= 0.0),
deleteIcon = deleteIcon ?? _kDefaultDeleteIcon, deleteIcon = deleteIcon ?? _kDefaultDeleteIcon,
super(key: key); super(key: key);
...@@ -1261,6 +1313,8 @@ class RawChip extends StatefulWidget ...@@ -1261,6 +1313,8 @@ class RawChip extends StatefulWidget
@override @override
final MaterialTapTargetSize materialTapTargetSize; final MaterialTapTargetSize materialTapTargetSize;
@override @override
final double elevation;
@override
final CircleBorder avatarBorder; final CircleBorder avatarBorder;
/// Whether or not to show a check mark when [selected] is true. /// Whether or not to show a check mark when [selected] is true.
...@@ -1512,7 +1566,7 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip ...@@ -1512,7 +1566,7 @@ class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip
Widget result = Material( Widget result = Material(
elevation: isTapping ? widget.pressElevation : 0.0, elevation: isTapping ? widget.pressElevation : widget.elevation,
animationDuration: pressedAnimationDuration, animationDuration: pressedAnimationDuration,
shape: shape, shape: shape,
clipBehavior: widget.clipBehavior, clipBehavior: widget.clipBehavior,
......
...@@ -1484,7 +1484,7 @@ void main() { ...@@ -1484,7 +1484,7 @@ void main() {
final ChipThemeData chipTheme = theme.chipTheme; final ChipThemeData chipTheme = theme.chipTheme;
InputChip inputChip = const InputChip(label: Text('Label'), pressElevation: 8.0); InputChip inputChip = const InputChip(label: Text('Label'));
Widget buildChip(ChipThemeData data) { Widget buildChip(ChipThemeData data) {
return _wrapForChip( return _wrapForChip(
...@@ -1498,12 +1498,18 @@ void main() { ...@@ -1498,12 +1498,18 @@ void main() {
await tester.pumpWidget(buildChip(chipTheme)); await tester.pumpWidget(buildChip(chipTheme));
expect(inputChip.pressElevation, 8.0); expect(inputChip.pressElevation, 8.0);
expect(inputChip.elevation, 0.0);
inputChip = const InputChip(label: Text('Label'), pressElevation: 12.0); inputChip = const InputChip(
label: Text('Label'),
pressElevation: 12.0,
elevation: 4.0,
);
await tester.pumpWidget(buildChip(chipTheme)); await tester.pumpWidget(buildChip(chipTheme));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(inputChip.pressElevation, 12.0); expect(inputChip.pressElevation, 12.0);
expect(inputChip.elevation, 4.0);
}); });
testWidgets('can be tapped outside of chip body', (WidgetTester tester) async { testWidgets('can be tapped outside of chip body', (WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment