@@ -14,6 +14,7 @@ import 'constants.dart';
1414import 'ink_well.dart' ;
1515import 'material.dart' ;
1616import 'material_state.dart' ;
17+ import 'material_state_mixin.dart' ;
1718import 'theme_data.dart' ;
1819
1920/// The base [StatefulWidget] class for buttons whose style is defined by a [ButtonStyle] object.
@@ -38,7 +39,6 @@ abstract class ButtonStyleButton extends StatefulWidget {
3839 required this .focusNode,
3940 required this .autofocus,
4041 required this .clipBehavior,
41- this .statesController,
4242 required this .child,
4343 }) : assert (autofocus != null ),
4444 assert (clipBehavior != null );
@@ -95,9 +95,6 @@ abstract class ButtonStyleButton extends StatefulWidget {
9595 /// {@macro flutter.widgets.Focus.autofocus}
9696 final bool autofocus;
9797
98- /// {@macro flutter.material.inkwell.statesController}
99- final MaterialStatesController ? statesController;
100-
10198 /// Typically the button's label.
10299 final Widget ? child;
103100
@@ -194,59 +191,34 @@ abstract class ButtonStyleButton extends StatefulWidget {
194191/// * [TextButton] , a simple button without a shadow.
195192/// * [ElevatedButton] , a filled button whose material elevates when pressed.
196193/// * [OutlinedButton] , similar to [TextButton] , but with an outline.
197- class _ButtonStyleState extends State <ButtonStyleButton > with TickerProviderStateMixin {
198- AnimationController ? controller;
199- double ? elevation;
200- Color ? backgroundColor;
201- MaterialStatesController ? internalStatesController;
202-
203- void handleStatesControllerChange () {
204- // Force a rebuild to resolve MaterialStateProperty properties
205- setState (() { });
206- }
207-
208- MaterialStatesController get statesController => widget.statesController ?? internalStatesController! ;
209-
210- void initStatesController () {
211- if (widget.statesController == null ) {
212- internalStatesController = MaterialStatesController ();
213- }
214- statesController.update (MaterialState .disabled, ! widget.enabled);
215- statesController.addListener (handleStatesControllerChange);
216- }
194+ class _ButtonStyleState extends State <ButtonStyleButton > with MaterialStateMixin , TickerProviderStateMixin {
195+ AnimationController ? _controller;
196+ double ? _elevation;
197+ Color ? _backgroundColor;
217198
218199 @override
219200 void initState () {
220201 super .initState ();
221- initStatesController ( );
202+ setMaterialState ( MaterialState .disabled, ! widget.enabled );
222203 }
223204
224205 @override
225- void didUpdateWidget (ButtonStyleButton oldWidget) {
226- super .didUpdateWidget (oldWidget);
227- if (widget.statesController != oldWidget.statesController) {
228- oldWidget.statesController? .removeListener (handleStatesControllerChange);
229- if (widget.statesController != null ) {
230- internalStatesController? .dispose ();
231- internalStatesController = null ;
232- }
233- initStatesController ();
234- }
235- if (widget.enabled != oldWidget.enabled) {
236- statesController.update (MaterialState .disabled, ! widget.enabled);
237- if (! widget.enabled) {
238- // The button may have been disabled while a press gesture is currently underway.
239- statesController.update (MaterialState .pressed, false );
240- }
241- }
206+ void dispose () {
207+ _controller? .dispose ();
208+ super .dispose ();
242209 }
243210
244211 @override
245- void dispose () {
246- statesController.removeListener (handleStatesControllerChange);
247- internalStatesController? .dispose ();
248- controller? .dispose ();
249- super .dispose ();
212+ void didUpdateWidget (ButtonStyleButton oldWidget) {
213+ super .didUpdateWidget (oldWidget);
214+ setMaterialState (MaterialState .disabled, ! widget.enabled);
215+ // If the button is disabled while a press gesture is currently ongoing,
216+ // InkWell makes a call to handleHighlightChanged. This causes an exception
217+ // because it calls setState in the middle of a build. To preempt this, we
218+ // manually update pressed to false when this situation occurs.
219+ if (isDisabled && isPressed) {
220+ removeMaterialState (MaterialState .pressed);
221+ }
250222 }
251223
252224 @override
@@ -265,9 +237,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
265237
266238 T ? resolve <T >(MaterialStateProperty <T >? Function (ButtonStyle ? style) getProperty) {
267239 return effectiveValue (
268- (ButtonStyle ? style) {
269- return getProperty (style)? .resolve (statesController.value);
270- },
240+ (ButtonStyle ? style) => getProperty (style)? .resolve (materialStates),
271241 );
272242 }
273243
@@ -284,7 +254,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
284254 final BorderSide ? resolvedSide = resolve <BorderSide ?>((ButtonStyle ? style) => style? .side);
285255 final OutlinedBorder ? resolvedShape = resolve <OutlinedBorder ?>((ButtonStyle ? style) => style? .shape);
286256
287- final MaterialStateMouseCursor mouseCursor = _MouseCursor (
257+ final MaterialStateMouseCursor resolvedMouseCursor = _MouseCursor (
288258 (Set <MaterialState > states) => effectiveValue ((ButtonStyle ? style) => style? .mouseCursor? .resolve (states)),
289259 );
290260
@@ -339,16 +309,16 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
339309 // animates its elevation but not its color. SKIA renders non-zero
340310 // elevations as a shadow colored fill behind the Material's background.
341311 if (resolvedAnimationDuration! > Duration .zero
342- && elevation != null
343- && backgroundColor != null
344- && elevation != resolvedElevation
345- && backgroundColor ! .value != resolvedBackgroundColor! .value
346- && backgroundColor ! .opacity == 1
312+ && _elevation != null
313+ && _backgroundColor != null
314+ && _elevation != resolvedElevation
315+ && _backgroundColor ! .value != resolvedBackgroundColor! .value
316+ && _backgroundColor ! .opacity == 1
347317 && resolvedBackgroundColor.opacity < 1
348318 && resolvedElevation == 0 ) {
349- if (controller ? .duration != resolvedAnimationDuration) {
350- controller ? .dispose ();
351- controller = AnimationController (
319+ if (_controller ? .duration != resolvedAnimationDuration) {
320+ _controller ? .dispose ();
321+ _controller = AnimationController (
352322 duration: resolvedAnimationDuration,
353323 vsync: this ,
354324 )
@@ -358,12 +328,12 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
358328 }
359329 });
360330 }
361- resolvedBackgroundColor = backgroundColor ; // Defer changing the background color.
362- controller ! .value = 0 ;
363- controller ! .forward ();
331+ resolvedBackgroundColor = _backgroundColor ; // Defer changing the background color.
332+ _controller ! .value = 0 ;
333+ _controller ! .forward ();
364334 }
365- elevation = resolvedElevation;
366- backgroundColor = resolvedBackgroundColor;
335+ _elevation = resolvedElevation;
336+ _backgroundColor = resolvedBackgroundColor;
367337
368338 final Widget result = ConstrainedBox (
369339 constraints: effectiveConstraints,
@@ -380,18 +350,24 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
380350 child: InkWell (
381351 onTap: widget.onPressed,
382352 onLongPress: widget.onLongPress,
383- onHover: widget.onHover,
384- mouseCursor: mouseCursor,
353+ onHighlightChanged: updateMaterialState (MaterialState .pressed),
354+ onHover: updateMaterialState (
355+ MaterialState .hovered,
356+ onChanged: widget.onHover,
357+ ),
358+ mouseCursor: resolvedMouseCursor,
385359 enableFeedback: resolvedEnableFeedback,
386360 focusNode: widget.focusNode,
387361 canRequestFocus: widget.enabled,
388- onFocusChange: widget.onFocusChange,
362+ onFocusChange: updateMaterialState (
363+ MaterialState .focused,
364+ onChanged: widget.onFocusChange,
365+ ),
389366 autofocus: widget.autofocus,
390367 splashFactory: resolvedSplashFactory,
391368 overlayColor: overlayColor,
392369 highlightColor: Colors .transparent,
393370 customBorder: resolvedShape,
394- statesController: statesController,
395371 child: IconTheme .merge (
396372 data: IconThemeData (color: resolvedForegroundColor),
397373 child: Padding (
0 commit comments