From b73dd0e81e407c4526d2137b17200199e2406c4b Mon Sep 17 00:00:00 2001 From: rami-a <2364772+rami-a@users.noreply.github.com> Date: Fri, 22 Feb 2019 15:50:39 -0500 Subject: [PATCH] [Material] Add ability to set shadow color and selected shadow color for chips and for chip themes (#28163) * Add ability to set shadow color for chips and for chip themes * Add selected shadow color as a property as well * Update phrasing of documentation * Address PR feedback --- packages/flutter/lib/src/material/chip.dart | 54 +++++++++++++++++++ .../flutter/lib/src/material/chip_theme.dart | 37 ++++++++++++- packages/flutter/test/material/chip_test.dart | 18 ++++++- .../test/material/chip_theme_test.dart | 16 ++++++ 4 files changed, 122 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index c7ffc9f67b..71f9b22ce3 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -118,6 +118,11 @@ abstract class ChipAttributes { /// /// Defaults to 0. The value is always non-negative. double get elevation; + + /// Color of the chip's shadow when the elevation is greater than 0. + /// + /// The default is [Colors.black]. + Color get shadowColor; } /// An interface for material design chips that can be deleted. @@ -309,6 +314,12 @@ abstract class SelectableChipAttributes { /// The chip is selected when [selected] is true. Color get selectedColor; + /// Color of the chip's shadow when the elevation is greater than 0 and the + /// chip is selected. + /// + /// The default is [Colors.black]. + Color get selectedShadowColor; + /// Tooltip string to be used for the body area (where the label and avatar /// are) of the chip. String get tooltip; @@ -486,6 +497,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri this.padding, this.materialTapTargetSize, this.elevation, + this.shadowColor, }) : assert(label != null), assert(clipBehavior != null), assert(elevation == null || elevation >= 0.0), @@ -519,6 +531,8 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri final MaterialTapTargetSize materialTapTargetSize; @override final double elevation; + @override + final Color shadowColor; @override Widget build(BuildContext context) { @@ -539,6 +553,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri padding: padding, materialTapTargetSize: materialTapTargetSize, elevation: elevation, + shadowColor: shadowColor, isEnabled: true, ); } @@ -628,6 +643,8 @@ class InputChip extends StatelessWidget this.padding, this.materialTapTargetSize, this.elevation, + this.shadowColor, + this.selectedShadowColor, this.avatarBorder = const CircleBorder(), }) : assert(selected != null), assert(isEnabled != null), @@ -682,6 +699,10 @@ class InputChip extends StatelessWidget @override final double elevation; @override + final Color shadowColor; + @override + final Color selectedShadowColor; + @override final ShapeBorder avatarBorder; @override @@ -710,6 +731,8 @@ class InputChip extends StatelessWidget padding: padding, materialTapTargetSize: materialTapTargetSize, elevation: elevation, + shadowColor: shadowColor, + selectedShadowColor: selectedShadowColor, isEnabled: isEnabled && (onSelected != null || onDeleted != null || onPressed != null), avatarBorder: avatarBorder, ); @@ -798,6 +821,8 @@ class ChoiceChip extends StatelessWidget this.padding, this.materialTapTargetSize, this.elevation, + this.shadowColor, + this.selectedShadowColor, this.avatarBorder = const CircleBorder(), }) : assert(selected != null), assert(label != null), @@ -839,6 +864,10 @@ class ChoiceChip extends StatelessWidget @override final double elevation; @override + final Color shadowColor; + @override + final Color selectedShadowColor; + @override final ShapeBorder avatarBorder; @override @@ -868,6 +897,8 @@ class ChoiceChip extends StatelessWidget isEnabled: isEnabled, materialTapTargetSize: materialTapTargetSize, elevation: elevation, + shadowColor: shadowColor, + selectedShadowColor: selectedShadowColor, avatarBorder: avatarBorder, ); } @@ -987,6 +1018,8 @@ class FilterChip extends StatelessWidget this.padding, this.materialTapTargetSize, this.elevation, + this.shadowColor, + this.selectedShadowColor, this.avatarBorder = const CircleBorder(), }) : assert(selected != null), assert(label != null), @@ -1028,6 +1061,10 @@ class FilterChip extends StatelessWidget @override final double elevation; @override + final Color shadowColor; + @override + final Color selectedShadowColor; + @override final ShapeBorder avatarBorder; @override @@ -1054,6 +1091,8 @@ class FilterChip extends StatelessWidget isEnabled: isEnabled, materialTapTargetSize: materialTapTargetSize, elevation: elevation, + shadowColor: shadowColor, + selectedShadowColor: selectedShadowColor, avatarBorder: avatarBorder, ); } @@ -1127,6 +1166,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip this.padding, this.materialTapTargetSize, this.elevation, + this.shadowColor, }) : assert(label != null), assert( onPressed != null, @@ -1163,6 +1203,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip final MaterialTapTargetSize materialTapTargetSize; @override final double elevation; + @override + final Color shadowColor; @override Widget build(BuildContext context) { @@ -1182,6 +1224,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip isEnabled: true, materialTapTargetSize: materialTapTargetSize, elevation: elevation, + shadowColor: shadowColor, ); } } @@ -1257,6 +1300,8 @@ class RawChip extends StatefulWidget this.backgroundColor, this.materialTapTargetSize, this.elevation, + this.shadowColor, + this.selectedShadowColor, this.avatarBorder = const CircleBorder(), }) : assert(label != null), assert(isEnabled != null), @@ -1311,6 +1356,10 @@ class RawChip extends StatefulWidget @override final double elevation; @override + final Color shadowColor; + @override + final Color selectedShadowColor; + @override final CircleBorder avatarBorder; /// Whether or not to show a check mark when [selected] is true. @@ -1550,6 +1599,7 @@ class _RawChipState extends State with TickerProviderStateMixin with TickerProviderStateMixin('disabledColor', disabledColor, defaultValue: defaultData.disabledColor)); properties.add(DiagnosticsProperty('selectedColor', selectedColor, defaultValue: defaultData.selectedColor)); properties.add(DiagnosticsProperty('secondarySelectedColor', secondarySelectedColor, defaultValue: defaultData.secondarySelectedColor)); + properties.add(DiagnosticsProperty('shadowColor', shadowColor, defaultValue: defaultData.shadowColor)); + properties.add(DiagnosticsProperty('selectedShadowColor', selectedShadowColor, defaultValue: defaultData.selectedShadowColor)); properties.add(DiagnosticsProperty('labelPadding', labelPadding, defaultValue: defaultData.labelPadding)); properties.add(DiagnosticsProperty('padding', padding, defaultValue: defaultData.padding)); properties.add(DiagnosticsProperty('shape', shape, defaultValue: defaultData.shape)); diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 07f220e1ec..f542d80c34 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -1485,7 +1485,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Chip elevation works correctly', (WidgetTester tester) async { + testWidgets('Chip elevation and shadow color work correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -1508,16 +1508,32 @@ void main() { await tester.pumpWidget(buildChip(chipTheme)); Material material = getMaterial(tester); expect(material.elevation, 0.0); + expect(material.shadowColor, Colors.black); inputChip = const InputChip( label: Text('Label'), elevation: 4.0, + shadowColor: Colors.green, + selectedShadowColor: Colors.blue, ); await tester.pumpWidget(buildChip(chipTheme)); await tester.pumpAndSettle(); material = getMaterial(tester); expect(material.elevation, 4.0); + expect(material.shadowColor, Colors.green); + + inputChip = const InputChip( + label: Text('Label'), + selected: true, + shadowColor: Colors.green, + selectedShadowColor: Colors.blue, + ); + + await tester.pumpWidget(buildChip(chipTheme)); + await tester.pumpAndSettle(); + material = getMaterial(tester); + expect(material.shadowColor, Colors.blue); }); testWidgets('can be tapped outside of chip body', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 79253b9ea8..3bca429112 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -120,6 +120,7 @@ void main() { backgroundColor: Colors.purple, deleteIconColor: Colors.purple.withAlpha(0x3d), elevation: 3.0, + shadowColor: Colors.pink, ); const bool value = false; Widget buildChip(ChipThemeData data) { @@ -162,6 +163,7 @@ void main() { expect(materialBox, paints..path(color: Color(customTheme.backgroundColor.value))); expect(material.elevation, customTheme.elevation); + expect(material.shadowColor, customTheme.shadowColor); }); testWidgets('ChipThemeData generates correct opacities for defaults', (WidgetTester tester) async { @@ -232,6 +234,8 @@ void main() { ).copyWith( elevation: 1.0, pressElevation: 4.0, + shadowColor: Colors.black, + selectedShadowColor: Colors.black, ); final ChipThemeData chipThemeWhite = ChipThemeData.fromDefaults( secondaryColor: Colors.white, @@ -242,6 +246,8 @@ void main() { labelPadding: const EdgeInsets.only(top: 8.0, bottom: 8.0), elevation: 5.0, pressElevation: 10.0, + shadowColor: Colors.white, + selectedShadowColor: Colors.white, ); final ChipThemeData lerp = ChipThemeData.lerp(chipThemeBlack, chipThemeWhite, 0.5); @@ -251,6 +257,8 @@ void main() { expect(lerp.disabledColor, equals(middleGrey.withAlpha(0x0c))); expect(lerp.selectedColor, equals(middleGrey.withAlpha(0x3d))); expect(lerp.secondarySelectedColor, equals(middleGrey.withAlpha(0x3d))); + expect(lerp.shadowColor, equals(middleGrey)); + expect(lerp.selectedShadowColor, equals(middleGrey)); expect(lerp.labelPadding, equals(const EdgeInsets.all(4.0))); expect(lerp.padding, equals(const EdgeInsets.all(3.0))); expect(lerp.shape, equals(isInstanceOf())); @@ -268,6 +276,8 @@ void main() { expect(lerpANull25.disabledColor, equals(Colors.black.withAlpha(0x03))); expect(lerpANull25.selectedColor, equals(Colors.black.withAlpha(0x0f))); expect(lerpANull25.secondarySelectedColor, equals(Colors.white.withAlpha(0x0f))); + expect(lerpANull25.shadowColor, equals(Colors.white.withAlpha(0x40))); + expect(lerpANull25.selectedShadowColor, equals(Colors.white.withAlpha(0x40))); expect(lerpANull25.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 2.0, right: 0.0, bottom: 2.0))); expect(lerpANull25.padding, equals(const EdgeInsets.all(0.5))); expect(lerpANull25.shape, equals(isInstanceOf())); @@ -283,6 +293,8 @@ void main() { expect(lerpANull75.disabledColor, equals(Colors.black.withAlpha(0x09))); expect(lerpANull75.selectedColor, equals(Colors.black.withAlpha(0x2e))); expect(lerpANull75.secondarySelectedColor, equals(Colors.white.withAlpha(0x2e))); + expect(lerpANull75.shadowColor, equals(Colors.white.withAlpha(0xbf))); + expect(lerpANull75.selectedShadowColor, equals(Colors.white.withAlpha(0xbf))); expect(lerpANull75.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 6.0, right: 0.0, bottom: 6.0))); expect(lerpANull75.padding, equals(const EdgeInsets.all(1.5))); expect(lerpANull75.shape, equals(isInstanceOf())); @@ -298,6 +310,8 @@ void main() { expect(lerpBNull25.disabledColor, equals(Colors.white.withAlpha(0x09))); expect(lerpBNull25.selectedColor, equals(Colors.white.withAlpha(0x2e))); expect(lerpBNull25.secondarySelectedColor, equals(Colors.black.withAlpha(0x2e))); + expect(lerpBNull25.shadowColor, equals(Colors.black.withAlpha(0xbf))); + expect(lerpBNull25.selectedShadowColor, equals(Colors.black.withAlpha(0xbf))); expect(lerpBNull25.labelPadding, equals(const EdgeInsets.only(left: 6.0, top: 0.0, right: 6.0, bottom: 0.0))); expect(lerpBNull25.padding, equals(const EdgeInsets.all(3.0))); expect(lerpBNull25.shape, equals(isInstanceOf())); @@ -313,6 +327,8 @@ void main() { expect(lerpBNull75.disabledColor, equals(Colors.white.withAlpha(0x03))); expect(lerpBNull75.selectedColor, equals(Colors.white.withAlpha(0x0f))); expect(lerpBNull75.secondarySelectedColor, equals(Colors.black.withAlpha(0x0f))); + expect(lerpBNull75.shadowColor, equals(Colors.black.withAlpha(0x40))); + expect(lerpBNull75.selectedShadowColor, equals(Colors.black.withAlpha(0x40))); expect(lerpBNull75.labelPadding, equals(const EdgeInsets.only(left: 2.0, top: 0.0, right: 2.0, bottom: 0.0))); expect(lerpBNull75.padding, equals(const EdgeInsets.all(1.0))); expect(lerpBNull75.shape, equals(isInstanceOf()));