Skip to content

Commit 0575932

Browse files
authored
Fix InkWell highlight and splash sometimes persists (#100880)
1 parent cb968c5 commit 0575932

File tree

2 files changed

+92
-4
lines changed

2 files changed

+92
-4
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -769,12 +769,12 @@ class _InkResponseState extends State<_InkResponseStateWidget>
769769
bool get _anyChildInkResponsePressed => _activeChildren.isNotEmpty;
770770

771771
void _simulateTap([Intent? intent]) {
772-
_startSplash(context: context);
772+
_startNewSplash(context: context);
773773
_handleTap();
774774
}
775775

776776
void _simulateLongPress() {
777-
_startSplash(context: context);
777+
_startNewSplash(context: context);
778778
_handleLongPress();
779779
}
780780

@@ -966,15 +966,15 @@ class _InkResponseState extends State<_InkResponseStateWidget>
966966
void _handleTapDown(TapDownDetails details) {
967967
if (_anyChildInkResponsePressed)
968968
return;
969-
_startSplash(details: details);
969+
_startNewSplash(details: details);
970970
widget.onTapDown?.call(details);
971971
}
972972

973973
void _handleTapUp(TapUpDetails details) {
974974
widget.onTapUp?.call(details);
975975
}
976976

977-
void _startSplash({TapDownDetails? details, BuildContext? context}) {
977+
void _startNewSplash({TapDownDetails? details, BuildContext? context}) {
978978
assert(details != null || context != null);
979979

980980
final Offset globalPosition;
@@ -988,6 +988,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
988988
final InteractiveInkFeature splash = _createInkFeature(globalPosition);
989989
_splashes ??= HashSet<InteractiveInkFeature>();
990990
_splashes!.add(splash);
991+
_currentSplash?.cancel();
991992
_currentSplash = splash;
992993
updateKeepAlive();
993994
updateHighlight(_HighlightType.pressed, value: true);
@@ -1014,6 +1015,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
10141015
void _handleDoubleTap() {
10151016
_currentSplash?.confirm();
10161017
_currentSplash = null;
1018+
updateHighlight(_HighlightType.pressed, value: false);
10171019
widget.onDoubleTap?.call();
10181020
}
10191021

packages/flutter/test/material/ink_well_test.dart

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,4 +1424,90 @@ void main() {
14241424
textDirection: TextDirection.ltr,
14251425
));
14261426
});
1427+
1428+
testWidgets('InkWell highlight should not survive after [onTapDown, onDoubleTap] sequence', (WidgetTester tester) async {
1429+
final List<String> log = <String>[];
1430+
1431+
await tester.pumpWidget(Directionality(
1432+
textDirection: TextDirection.ltr,
1433+
child: Material(
1434+
child: Center(
1435+
child: InkWell(
1436+
onTap: () {
1437+
log.add('tap');
1438+
},
1439+
onDoubleTap: () {
1440+
log.add('double-tap');
1441+
},
1442+
onTapDown: (TapDownDetails details) {
1443+
log.add('tap-down');
1444+
},
1445+
onTapCancel: () {
1446+
log.add('tap-cancel');
1447+
},
1448+
),
1449+
),
1450+
),
1451+
));
1452+
1453+
final Offset taplocation = tester.getRect(find.byType(InkWell)).center;
1454+
1455+
final TestGesture gesture = await tester.startGesture(taplocation);
1456+
await tester.pump(const Duration(milliseconds: 100));
1457+
expect(log, equals(<String>['tap-down']));
1458+
await gesture.up();
1459+
await tester.pump(const Duration(milliseconds: 100));
1460+
await tester.tap(find.byType(InkWell));
1461+
await tester.pump(const Duration(milliseconds: 100));
1462+
expect(log, equals(<String>['tap-down', 'double-tap']));
1463+
1464+
await tester.pumpAndSettle();
1465+
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
1466+
expect(inkFeatures, paintsExactlyCountTimes(#drawRect, 0));
1467+
});
1468+
1469+
testWidgets('InkWell splash should not survive after [onTapDown, onTapDown, onTapCancel, onDoubleTap] sequence', (WidgetTester tester) async {
1470+
final List<String> log = <String>[];
1471+
1472+
await tester.pumpWidget(Directionality(
1473+
textDirection: TextDirection.ltr,
1474+
child: Material(
1475+
child: Center(
1476+
child: InkWell(
1477+
onTap: () {
1478+
log.add('tap');
1479+
},
1480+
onDoubleTap: () {
1481+
log.add('double-tap');
1482+
},
1483+
onTapDown: (TapDownDetails details) {
1484+
log.add('tap-down');
1485+
},
1486+
onTapCancel: () {
1487+
log.add('tap-cancel');
1488+
},
1489+
),
1490+
),
1491+
),
1492+
));
1493+
1494+
final Offset tapLocation = tester.getRect(find.byType(InkWell)).center;
1495+
1496+
final TestGesture gesture1 = await tester.startGesture(tapLocation);
1497+
await tester.pump(const Duration(milliseconds: 100));
1498+
expect(log, equals(<String>['tap-down']));
1499+
await gesture1.up();
1500+
await tester.pump(const Duration(milliseconds: 100));
1501+
1502+
final TestGesture gesture2 = await tester.startGesture(tapLocation);
1503+
await tester.pump(const Duration(milliseconds: 100));
1504+
expect(log, equals(<String>['tap-down', 'tap-down']));
1505+
await gesture2.up();
1506+
await tester.pump(const Duration(milliseconds: 100));
1507+
expect(log, equals(<String>['tap-down', 'tap-down', 'tap-cancel', 'double-tap']));
1508+
1509+
await tester.pumpAndSettle();
1510+
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
1511+
expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0));
1512+
});
14271513
}

0 commit comments

Comments
 (0)