Make chip.dart use WidgetStatesController (#161487)

Fixes https://github.com/flutter/flutter/issues/128289

Follow up of https://github.com/flutter/flutter/pull/128507 and
https://github.com/flutter/flutter/pull/159422

- Makes `RawChip` use `WidgetStatesController` instead of
`MaterialStateMixin`
- Remove references of `MaterialState` to replace them with
`WidgetState`

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com>
This commit is contained in:
Valentin Vignal
2025-03-24 17:55:06 +01:00
committed by GitHub
parent 8128f08603
commit 096c4ace35

View File

@@ -28,7 +28,6 @@ import 'ink_well.dart';
import 'material.dart';
import 'material_localizations.dart';
import 'material_state.dart';
import 'material_state_mixin.dart';
import 'text_theme.dart';
import 'theme.dart';
import 'theme_data.dart';
@@ -163,7 +162,7 @@ abstract interface class ChipAttributes {
/// Resolves in the following states:
/// * [WidgetState.selected].
/// * [WidgetState.disabled].
MaterialStateProperty<Color?>? get color;
WidgetStateProperty<Color?>? get color;
/// Color to be used for the unselected, enabled chip's background.
///
@@ -739,7 +738,7 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri
@override
final bool autofocus;
@override
final MaterialStateProperty<Color?>? color;
final WidgetStateProperty<Color?>? color;
@override
final Color? backgroundColor;
@override
@@ -949,7 +948,7 @@ class RawChip extends StatefulWidget
@override
final bool autofocus;
@override
final MaterialStateProperty<Color?>? color;
final WidgetStateProperty<Color?>? color;
@override
final Color? backgroundColor;
@override
@@ -997,8 +996,7 @@ class RawChip extends StatefulWidget
State<RawChip> createState() => _RawChipState();
}
class _RawChipState extends State<RawChip>
with MaterialStateMixin, TickerProviderStateMixin<RawChip> {
class _RawChipState extends State<RawChip> with TickerProviderStateMixin<RawChip> {
static const Duration pressedAnimationDuration = Duration(milliseconds: 75);
late AnimationController selectController;
@@ -1011,6 +1009,8 @@ class _RawChipState extends State<RawChip>
late CurvedAnimation enableAnimation;
late CurvedAnimation selectionFade;
final WidgetStatesController statesController = WidgetStatesController();
bool get hasDeleteButton => widget.onDeleted != null;
bool get hasAvatar => widget.avatar != null;
@@ -1027,8 +1027,10 @@ class _RawChipState extends State<RawChip>
void initState() {
assert(widget.onSelected == null || widget.onPressed == null);
super.initState();
setMaterialState(MaterialState.disabled, !widget.isEnabled);
setMaterialState(MaterialState.selected, widget.selected);
statesController
..update(WidgetState.disabled, !widget.isEnabled)
..update(WidgetState.selected, widget.selected)
..addListener(() => setState(() {}));
selectController = AnimationController(
duration: widget.chipAnimationStyle?.selectAnimation?.duration ?? _kSelectDuration,
reverseDuration: widget.chipAnimationStyle?.selectAnimation?.reverseDuration,
@@ -1091,6 +1093,7 @@ class _RawChipState extends State<RawChip>
deleteDrawerAnimation.dispose();
enableAnimation.dispose();
selectionFade.dispose();
statesController.dispose();
super.dispose();
}
@@ -1098,7 +1101,7 @@ class _RawChipState extends State<RawChip>
if (!canTap) {
return;
}
setMaterialState(MaterialState.pressed, true);
statesController.update(WidgetState.pressed, true);
setState(() {
_isTapping = true;
});
@@ -1108,7 +1111,7 @@ class _RawChipState extends State<RawChip>
if (!canTap) {
return;
}
setMaterialState(MaterialState.pressed, false);
statesController.update(WidgetState.pressed, false);
setState(() {
_isTapping = false;
});
@@ -1118,7 +1121,7 @@ class _RawChipState extends State<RawChip>
if (!canTap) {
return;
}
setMaterialState(MaterialState.pressed, false);
statesController.update(WidgetState.pressed, false);
setState(() {
_isTapping = false;
});
@@ -1129,12 +1132,12 @@ class _RawChipState extends State<RawChip>
OutlinedBorder _getShape(ThemeData theme, ChipThemeData chipTheme, ChipThemeData chipDefaults) {
final BorderSide? resolvedSide =
MaterialStateProperty.resolveAs<BorderSide?>(widget.side, materialStates) ??
MaterialStateProperty.resolveAs<BorderSide?>(chipTheme.side, materialStates);
WidgetStateProperty.resolveAs<BorderSide?>(widget.side, statesController.value) ??
WidgetStateProperty.resolveAs<BorderSide?>(chipTheme.side, statesController.value);
final OutlinedBorder resolvedShape =
MaterialStateProperty.resolveAs<OutlinedBorder?>(widget.shape, materialStates) ??
MaterialStateProperty.resolveAs<OutlinedBorder?>(chipTheme.shape, materialStates) ??
MaterialStateProperty.resolveAs<OutlinedBorder?>(chipDefaults.shape, materialStates)
WidgetStateProperty.resolveAs<OutlinedBorder?>(widget.shape, statesController.value) ??
WidgetStateProperty.resolveAs<OutlinedBorder?>(chipTheme.shape, statesController.value) ??
WidgetStateProperty.resolveAs<OutlinedBorder?>(chipDefaults.shape, statesController.value)
// TODO(tahatesser): Remove this fallback when Material 2 is deprecated.
??
const StadiumBorder();
@@ -1150,19 +1153,19 @@ class _RawChipState extends State<RawChip>
}
Color? resolveColor({
MaterialStateProperty<Color?>? color,
WidgetStateProperty<Color?>? color,
Color? selectedColor,
Color? backgroundColor,
Color? disabledColor,
MaterialStateProperty<Color?>? defaultColor,
WidgetStateProperty<Color?>? defaultColor,
}) {
return _IndividualOverrides(
color: color,
selectedColor: selectedColor,
backgroundColor: backgroundColor,
disabledColor: disabledColor,
).resolve(materialStates) ??
defaultColor?.resolve(materialStates);
).resolve(statesController.value) ??
defaultColor?.resolve(statesController.value);
}
/// Picks between three different colors, depending upon the state of two
@@ -1216,7 +1219,7 @@ class _RawChipState extends State<RawChip>
super.didUpdateWidget(oldWidget);
if (oldWidget.isEnabled != widget.isEnabled) {
setState(() {
setMaterialState(MaterialState.disabled, !widget.isEnabled);
statesController.update(WidgetState.disabled, !widget.isEnabled);
if (widget.isEnabled) {
enableController.forward();
} else {
@@ -1235,7 +1238,7 @@ class _RawChipState extends State<RawChip>
}
if (oldWidget.selected != widget.selected) {
setState(() {
setMaterialState(MaterialState.selected, widget.selected);
statesController.update(WidgetState.selected, widget.selected);
if (widget.selected) {
selectController.forward();
} else {
@@ -1360,9 +1363,9 @@ class _RawChipState extends State<RawChip>
widget.deleteIconBoxConstraints ?? chipTheme.deleteIconBoxConstraints;
final TextStyle effectiveLabelStyle = labelStyle.merge(widget.labelStyle);
final Color? resolvedLabelColor = MaterialStateProperty.resolveAs<Color?>(
final Color? resolvedLabelColor = WidgetStateProperty.resolveAs<Color?>(
effectiveLabelStyle.color,
materialStates,
statesController.value,
);
final TextStyle resolvedLabelStyle = effectiveLabelStyle.copyWith(color: resolvedLabelColor);
final Widget? avatar =
@@ -1398,14 +1401,21 @@ class _RawChipState extends State<RawChip>
shape: resolvedShape,
clipBehavior: widget.clipBehavior,
child: InkWell(
onFocusChange: updateMaterialState(MaterialState.focused),
onFocusChange: (bool value) {
statesController.update(WidgetState.focused, value);
},
focusNode: widget.focusNode,
autofocus: widget.autofocus,
canRequestFocus: widget.isEnabled,
onTap: canTap ? _handleTap : null,
onTapDown: canTap ? _handleTapDown : null,
onTapCancel: canTap ? _handleTapCancel : null,
onHover: canTap ? updateMaterialState(MaterialState.hovered) : null,
onHover:
canTap
? (bool value) {
statesController.update(WidgetState.hovered, value);
}
: null,
mouseCursor: widget.mouseCursor,
hoverColor: (widget.color ?? chipTheme.color) == null ? null : Colors.transparent,
customBorder: resolvedShape,
@@ -1493,26 +1503,26 @@ class _RawChipState extends State<RawChip>
}
}
class _IndividualOverrides extends MaterialStateProperty<Color?> {
class _IndividualOverrides extends WidgetStateProperty<Color?> {
_IndividualOverrides({this.color, this.backgroundColor, this.selectedColor, this.disabledColor});
final MaterialStateProperty<Color?>? color;
final WidgetStateProperty<Color?>? color;
final Color? backgroundColor;
final Color? selectedColor;
final Color? disabledColor;
@override
Color? resolve(Set<MaterialState> states) {
Color? resolve(Set<WidgetState> states) {
if (color != null) {
return color!.resolve(states);
}
if (states.contains(MaterialState.selected) && states.contains(MaterialState.disabled)) {
if (states.contains(WidgetState.selected) && states.contains(WidgetState.disabled)) {
return selectedColor;
}
if (states.contains(MaterialState.disabled)) {
if (states.contains(WidgetState.disabled)) {
return disabledColor;
}
if (states.contains(MaterialState.selected)) {
if (states.contains(WidgetState.selected)) {
return selectedColor;
}
return backgroundColor;