Skip to content

Commit 467c970

Browse files
authored
Introduce MaterialState color property for chips (#128584)
fixes flutter/flutter#115827 fixes flutter/flutter#101325 ### Description 1. This PR adds a new MaterialState `color` property to all the chips (this makes it possible to customize chips in all states from the M3 specs). 2. Updated defaults to use the new MaterialState `color` property. 3. Updated and added new tests to all the chip test classes. <details> <summary>code sample</summary> ```dart import 'package:flutter/material.dart'; const Color disabledColor = Colors.black26; const Color backgroundColor = Colors.cyan; final Color disabledSelectedColor = Colors.red.shade100; const Color selectedColor = Colors.amber; final MaterialStateProperty<Color> color = MaterialStateProperty.resolveWith((Set<MaterialState> states) { if (states.contains(MaterialState.disabled) && states.contains(MaterialState.selected)) { return disabledSelectedColor; } if (states.contains(MaterialState.disabled)) { return disabledColor; } if (states.contains(MaterialState.selected)) { return selectedColor; } return backgroundColor; }); void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @OverRide Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, // chipTheme: ChipThemeData(color: color), ), home: const Example(), ); } } class Example extends StatefulWidget { const Example({super.key}); @OverRide State<Example> createState() => _ExampleState(); } class _ExampleState extends State<Example> { bool enabled = false; bool selected = true; @OverRide Widget build(BuildContext context) { const Widget verticalSpace = SizedBox(height: 20); return Scaffold( body: Center( child: Column( children: <Widget>[ const SizedBox(height: 25), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ const Card( elevation: 0.0, color: disabledColor, child: Padding( padding: EdgeInsets.all(8.0), child: Text('disabledColor'), ), ), const Card( elevation: 0.0, color: backgroundColor, child: Padding( padding: EdgeInsets.all(8.0), child: Text('backgroundColor'), ), ), Card( elevation: 0.0, color: disabledSelectedColor, child: const Padding( padding: EdgeInsets.all(8.0), child: Text('disabledSelectedColor'), ), ), const Card( elevation: 0.0, color: selectedColor, child: Padding( padding: EdgeInsets.all(8.0), child: Text('selectedColor'), ), ), ], ), const Spacer(), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RawChip( selected: selected, selectedColor: selectedColor, color: color, label: const Text('RawChip'), isEnabled: enabled, onSelected: enabled ? (bool value) {} : null, ), verticalSpace, InputChip( isEnabled: enabled, selected: selected, selectedColor: selectedColor, color: color, label: const Text('InputChip'), onSelected: enabled ? (bool value) {} : null, ), ], ), Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ FilterChip( selected: selected, selectedColor: selectedColor, color: color, label: const Text('FilterChip'), onSelected: enabled ? (bool value) {} : null, ), verticalSpace, FilterChip.elevated( selected: selected, selectedColor: selectedColor, color: color, label: const Text('FilterChip.elevated'), onSelected: enabled ? (bool value) {} : null, ), ], ), Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ ChoiceChip( selected: selected, selectedColor: selectedColor, color: color, label: const Text('ChoiceChip'), onSelected: enabled ? (bool value) {} : null, ), verticalSpace, ChoiceChip.elevated( selected: selected, selectedColor: selectedColor, color: color, label: const Text('ChoiceChip.elevated'), onSelected: enabled ? (bool value) {} : null, ), ], ), ], ), const Spacer(), Row( children: <Widget>[ Flexible( child: SwitchListTile( title: const Text('Enabled'), value: enabled, onChanged: (bool value) { setState(() => enabled = value); }, ), ), Flexible( child: SwitchListTile( title: const Text('Selected'), value: selected, onChanged: (bool value) { setState(() => selected = value); }, ), ), ], ) ], ), ), ); } } ``` </details> ### Before (not possible to customize disabled and selected chips) ![Screenshot 2023-06-13 at 16 27 13](https://github.com/flutter/flutter/assets/48603081/633f09f7-16a1-469e-b326-b9cc0ed59242) ### After (using disabled and selected chips using the new MaterialState `color` property) ![Screenshot 2023-06-13 at 16 26 53](https://github.com/flutter/flutter/assets/48603081/7f5dffb7-4074-4268-87c0-c059c2da67a8)
1 parent 62a1c8e commit 467c970

16 files changed

+1271
-138
lines changed

dev/tools/gen_defaults/lib/action_chip_template.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,15 @@ class _${blockName}DefaultsM3 extends ChipThemeData {
4141
TextStyle? get labelStyle => ${textStyle("$tokenGroup.label-text")};
4242
4343
@override
44-
Color? get backgroundColor => ${componentColor("$tokenGroup$flatVariant.container")};
44+
MaterialStateProperty<Color?>? get color =>
45+
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
46+
if (states.contains(MaterialState.disabled)) {
47+
return _chipVariant == _ChipVariant.flat
48+
? ${componentColor("$tokenGroup$flatVariant.disabled.container")}
49+
: ${componentColor("$tokenGroup$elevatedVariant.disabled.container")};
50+
}
51+
return ${componentColor("$tokenGroup$flatVariant.container")};
52+
});
4553
4654
@override
4755
Color? get shadowColor => _chipVariant == _ChipVariant.flat
@@ -51,17 +59,9 @@ class _${blockName}DefaultsM3 extends ChipThemeData {
5159
@override
5260
Color? get surfaceTintColor => ${colorOrTransparent("$tokenGroup.container.surface-tint-layer.color")};
5361
54-
@override
55-
Color? get selectedColor => ${componentColor("$tokenGroup$flatVariant.selected.container")};
56-
5762
@override
5863
Color? get checkmarkColor => ${color("$tokenGroup.with-icon.selected.icon.color")};
5964
60-
@override
61-
Color? get disabledColor => _chipVariant == _ChipVariant.flat
62-
? ${componentColor("$tokenGroup$flatVariant.disabled.container")}
63-
: ${componentColor("$tokenGroup$elevatedVariant.disabled.container")};
64-
6565
@override
6666
Color? get deleteIconColor => ${color("$tokenGroup.with-icon.selected.icon.color")};
6767

dev/tools/gen_defaults/lib/chip_template.dart

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,17 @@ class _${blockName}DefaultsM3 extends ChipThemeData {
3232
TextStyle? get labelStyle => ${textStyle("$tokenGroup.label-text")};
3333
3434
@override
35-
Color? get backgroundColor => ${componentColor("$tokenGroup$variant.container")};
35+
MaterialStateProperty<Color?>? get color => null; // Subclasses override this getter
3636
3737
@override
3838
Color? get shadowColor => ${colorOrTransparent("$tokenGroup.container.shadow-color")};
3939
4040
@override
4141
Color? get surfaceTintColor => ${colorOrTransparent("$tokenGroup.container.surface-tint-layer.color")};
4242
43-
@override
44-
Color? get selectedColor => ${componentColor("$tokenGroup$variant.selected.container")};
45-
4643
@override
4744
Color? get checkmarkColor => ${color("$tokenGroup.with-icon.selected.icon.color")};
4845
49-
@override
50-
Color? get disabledColor => ${componentColor("$tokenGroup$variant.disabled.container")};
51-
5246
@override
5347
Color? get deleteIconColor => ${color("$tokenGroup.with-icon.selected.icon.color")};
5448

dev/tools/gen_defaults/lib/filter_chip_template.dart

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,27 @@ class _${blockName}DefaultsM3 extends ChipThemeData {
4646
TextStyle? get labelStyle => ${textStyle("$tokenGroup.label-text")};
4747
4848
@override
49-
Color? get backgroundColor => ${componentColor("$tokenGroup$flatVariant.container")};
49+
MaterialStateProperty<Color?>? get color =>
50+
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
51+
if (states.contains(MaterialState.selected) && states.contains(MaterialState.disabled)) {
52+
return _chipVariant == _ChipVariant.flat
53+
? ${componentColor("$tokenGroup$flatVariant.disabled.selected.container")}
54+
: ${componentColor("$tokenGroup$elevatedVariant.disabled.container")};
55+
}
56+
if (states.contains(MaterialState.disabled)) {
57+
return _chipVariant == _ChipVariant.flat
58+
? ${componentColor("$tokenGroup$flatVariant.disabled.unselected.container")}
59+
: ${componentColor("$tokenGroup$elevatedVariant.disabled.container")};
60+
}
61+
if (states.contains(MaterialState.selected)) {
62+
return _chipVariant == _ChipVariant.flat
63+
? ${componentColor("$tokenGroup$flatVariant.selected.container")}
64+
: ${componentColor("$tokenGroup$elevatedVariant.selected.container")};
65+
}
66+
return _chipVariant == _ChipVariant.flat
67+
? ${componentColor("$tokenGroup$flatVariant.container")}
68+
: ${componentColor("$tokenGroup$elevatedVariant.container")};
69+
});
5070
5171
@override
5272
Color? get shadowColor => _chipVariant == _ChipVariant.flat
@@ -56,25 +76,9 @@ class _${blockName}DefaultsM3 extends ChipThemeData {
5676
@override
5777
Color? get surfaceTintColor => ${colorOrTransparent("$tokenGroup.container.surface-tint-layer.color")};
5878
59-
@override
60-
Color? get selectedColor => _chipVariant == _ChipVariant.flat
61-
? isEnabled
62-
? ${componentColor("$tokenGroup$flatVariant.selected.container")}
63-
: ${componentColor("$tokenGroup$flatVariant.disabled.selected.container")}
64-
: isEnabled
65-
? ${componentColor("$tokenGroup$elevatedVariant.selected.container")}
66-
: ${componentColor("$tokenGroup$elevatedVariant.disabled.container")};
67-
6879
@override
6980
Color? get checkmarkColor => ${color("$tokenGroup.with-leading-icon.selected.leading-icon.color")};
7081
71-
@override
72-
Color? get disabledColor => _chipVariant == _ChipVariant.flat
73-
? isSelected
74-
? ${componentColor("$tokenGroup$flatVariant.disabled.selected.container")}
75-
: ${componentColor("$tokenGroup$flatVariant.disabled.unselected.container")}
76-
: ${componentColor("$tokenGroup$elevatedVariant.disabled.container")};
77-
7882
@override
7983
Color? get deleteIconColor => ${color("$tokenGroup.with-trailing-icon.selected.trailing-icon.color")};
8084

dev/tools/gen_defaults/lib/input_chip_template.dart

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,29 @@ class _${blockName}DefaultsM3 extends ChipThemeData {
3333
TextStyle? get labelStyle => ${textStyle("$tokenGroup.label-text")};
3434
3535
@override
36-
Color? get backgroundColor => ${componentColor("$tokenGroup$variant.container")};
36+
MaterialStateProperty<Color?>? get color =>
37+
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
38+
if (states.contains(MaterialState.selected) && states.contains(MaterialState.disabled)) {
39+
return ${componentColor("$tokenGroup$variant.disabled.selected.container")};
40+
}
41+
if (states.contains(MaterialState.disabled)) {
42+
return ${componentColor("$tokenGroup$variant.disabled.container")};
43+
}
44+
if (states.contains(MaterialState.selected)) {
45+
return ${componentColor("$tokenGroup$variant.selected.container")};
46+
}
47+
return ${componentColor("$tokenGroup$variant.container")};
48+
});
3749
3850
@override
3951
Color? get shadowColor => ${colorOrTransparent("$tokenGroup.container.shadow-color")};
4052
4153
@override
4254
Color? get surfaceTintColor => ${colorOrTransparent("$tokenGroup.container.surface-tint-layer.color")};
4355
44-
@override
45-
Color? get selectedColor => isEnabled
46-
? ${componentColor("$tokenGroup$variant.selected.container")}
47-
: ${componentColor("$tokenGroup$variant.disabled.selected.container")};
48-
4956
@override
5057
Color? get checkmarkColor => ${color("$tokenGroup.with-icon.selected.icon.color")};
5158
52-
@override
53-
Color? get disabledColor => ${componentColor("$tokenGroup$variant.disabled.container")};
54-
5559
@override
5660
Color? get deleteIconColor => ${color("$tokenGroup.with-trailing-icon.selected.trailing-icon.color")};
5761

packages/flutter/lib/src/material/action_chip.dart

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'chip_theme.dart';
1010
import 'color_scheme.dart';
1111
import 'colors.dart';
1212
import 'debug.dart';
13+
import 'material_state.dart';
1314
import 'text_theme.dart';
1415
import 'theme.dart';
1516
import 'theme_data.dart';
@@ -81,6 +82,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
8182
this.clipBehavior = Clip.none,
8283
this.focusNode,
8384
this.autofocus = false,
85+
this.color,
8486
this.backgroundColor,
8587
this.disabledColor,
8688
this.padding,
@@ -113,6 +115,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
113115
this.clipBehavior = Clip.none,
114116
this.focusNode,
115117
this.autofocus = false,
118+
this.color,
116119
this.backgroundColor,
117120
this.disabledColor,
118121
this.padding,
@@ -151,6 +154,8 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
151154
@override
152155
final bool autofocus;
153156
@override
157+
final MaterialStateProperty<Color?>? color;
158+
@override
154159
final Color? backgroundColor;
155160
@override
156161
final Color? disabledColor;
@@ -188,6 +193,7 @@ class ActionChip extends StatelessWidget implements ChipAttributes, TappableChip
188193
pressElevation: pressElevation,
189194
tooltip: tooltip,
190195
labelStyle: labelStyle,
196+
color: color,
191197
backgroundColor: backgroundColor,
192198
side: side,
193199
shape: shape,
@@ -239,7 +245,15 @@ class _ActionChipDefaultsM3 extends ChipThemeData {
239245
TextStyle? get labelStyle => _textTheme.labelLarge;
240246

241247
@override
242-
Color? get backgroundColor => null;
248+
MaterialStateProperty<Color?>? get color =>
249+
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
250+
if (states.contains(MaterialState.disabled)) {
251+
return _chipVariant == _ChipVariant.flat
252+
? null
253+
: _colors.onSurface.withOpacity(0.12);
254+
}
255+
return null;
256+
});
243257

244258
@override
245259
Color? get shadowColor => _chipVariant == _ChipVariant.flat
@@ -249,17 +263,9 @@ class _ActionChipDefaultsM3 extends ChipThemeData {
249263
@override
250264
Color? get surfaceTintColor => _colors.surfaceTint;
251265

252-
@override
253-
Color? get selectedColor => null;
254-
255266
@override
256267
Color? get checkmarkColor => null;
257268

258-
@override
259-
Color? get disabledColor => _chipVariant == _ChipVariant.flat
260-
? null
261-
: _colors.onSurface.withOpacity(0.12);
262-
263269
@override
264270
Color? get deleteIconColor => null;
265271

0 commit comments

Comments
 (0)