diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index bdba4f7cf859..90d1c53139ec 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -842,14 +842,14 @@ class _InkResponseState extends State<_InkResponseStateWidget> widget.radius != oldWidget.radius || widget.borderRadius != oldWidget.borderRadius || widget.highlightShape != oldWidget.highlightShape) { - final InkHighlight? hoverHighLight = _highlights[_HighlightType.hover]; - if (hoverHighLight != null) { - hoverHighLight.dispose(); + final InkHighlight? hoverHighlight = _highlights[_HighlightType.hover]; + if (hoverHighlight != null) { + hoverHighlight.dispose(); updateHighlight(_HighlightType.hover, value: _hovering, callOnHover: false); } - final InkHighlight? focusHighLight = _highlights[_HighlightType.focus]; - if (focusHighLight != null) { - focusHighLight.dispose(); + final InkHighlight? focusHighlight = _highlights[_HighlightType.focus]; + if (focusHighlight != null) { + focusHighlight.dispose(); // Do not call updateFocusHighlights() here because it is called below } } @@ -857,6 +857,13 @@ class _InkResponseState extends State<_InkResponseStateWidget> statesController.update(MaterialState.disabled, !enabled); if (!enabled) { statesController.update(MaterialState.pressed, false); + // Remove the existing hover highlight immediately when enabled is false. + // Do not rely on updateHighlight or InkHighlight.deactivate to not break + // the expected lifecycle which is updating _hovering when the mouse exit. + // Manually updating _hovering here or calling InkHighlight.deactivate + // will lead to onHover not being called or call when it is not allowed. + final InkHighlight? hoverHighlight = _highlights[_HighlightType.hover]; + hoverHighlight?.dispose(); } // Don't call widget.onHover because many widgets, including the button // widgets, apply setState to an ancestor context from onHover. @@ -937,7 +944,7 @@ class _InkResponseState extends State<_InkResponseStateWidget> _highlights[type] = InkHighlight( controller: Material.of(context), referenceBox: referenceBox, - color: resolvedOverlayColor, + color: enabled ? resolvedOverlayColor : resolvedOverlayColor.withAlpha(0), shape: widget.highlightShape, radius: widget.radius, borderRadius: widget.borderRadius, diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index dd0d5dafbc96..ffe018b85180 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -1722,6 +1722,56 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(hover, false); }); + testWidgets('hovered ink well draws a transparent highlight when disabled', (WidgetTester tester) async { + Widget buildFrame({ required bool enabled }) { + return Material( + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + width: 100, + height: 100, + child: InkWell( + onTap: enabled ? () { } : null, + onHover: (bool value) { }, + hoverColor: const Color(0xff00ff00), + ), + ), + ), + ), + ); + } + + await tester.pumpWidget(buildFrame(enabled: true)); + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + + // Hover the enabled InkWell. + await gesture.moveTo(tester.getCenter(find.byType(InkWell))); + await tester.pumpAndSettle(); + expect( + find.byType(Material), + paints + ..rect( + color: const Color(0xff00ff00), + rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), + ) + ); + + // Disable the hovered InkWell. + await tester.pumpWidget(buildFrame(enabled: false)); + await tester.pumpAndSettle(); + expect( + find.byType(Material), + paints + ..rect( + color: const Color(0x0000ff00), + rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), + ) + ); + }); + + testWidgets('Changing InkWell.enabled should not trigger TextButton setState()', (WidgetTester tester) async { Widget buildFrame({ required bool enabled }) { return Material( diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index c830d0237184..acc2f4fbb5f6 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -979,7 +979,7 @@ void main() { paints ..rect() ..rect( - color: Colors.orange[500], + color: Colors.orange[500]!.withAlpha(0), rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), ) ..rect(