Skip to content

Commit 2cb2e84

Browse files
authored
Add more InkWell tests (#115634)
Co-authored-by: Bruno Leroux <[email protected]>
1 parent 9807761 commit 2cb2e84

File tree

2 files changed

+208
-26
lines changed

2 files changed

+208
-26
lines changed

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -438,13 +438,15 @@ class InkResponse extends StatelessWidget {
438438
/// * [splashFactory], which defines the appearance of the splash.
439439
final double? radius;
440440

441-
/// The clipping radius of the containing rect. This is effective only if
442-
/// [customBorder] is null.
441+
/// The border radius of the containing rectangle. This is effective only if
442+
/// [highlightShape] is [BoxShape.rectangle].
443443
///
444444
/// If this is null, it is interpreted as [BorderRadius.zero].
445445
final BorderRadius? borderRadius;
446446

447-
/// The custom clip border which overrides [borderRadius].
447+
/// The custom clip border.
448+
///
449+
/// If this is null, the ink response will not clip its content.
448450
final ShapeBorder? customBorder;
449451

450452
/// The color of the ink response when the parent widget is focused. If this

packages/flutter/test/material/ink_well_test.dart

+203-23
Original file line numberDiff line numberDiff line change
@@ -348,13 +348,13 @@ void main() {
348348
width: 100,
349349
height: 100,
350350
child: InkWell(
351-
hoverColor: const Color(0xff00ff00),
352-
splashColor: splashColor,
353-
focusColor: const Color(0xff0000ff),
354-
highlightColor: const Color(0xf00fffff),
355-
onTap: () { },
356-
onLongPress: () { },
357-
onHover: (bool hover) { },
351+
hoverColor: const Color(0xff00ff00),
352+
splashColor: splashColor,
353+
focusColor: const Color(0xff0000ff),
354+
highlightColor: const Color(0xf00fffff),
355+
onTap: () { },
356+
onLongPress: () { },
357+
onHover: (bool hover) { },
358358
),
359359
),
360360
),
@@ -386,21 +386,21 @@ void main() {
386386
width: 100,
387387
height: 100,
388388
child: InkWell(
389-
overlayColor: MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
390-
if (states.contains(MaterialState.hovered)) {
391-
return const Color(0xff00ff00);
392-
}
393-
if (states.contains(MaterialState.focused)) {
394-
return const Color(0xff0000ff);
395-
}
396-
if (states.contains(MaterialState.pressed)) {
397-
return splashColor;
398-
}
399-
return const Color(0xffbadbad); // Shouldn't happen.
400-
}),
401-
onTap: () { },
402-
onLongPress: () { },
403-
onHover: (bool hover) { },
389+
overlayColor: MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
390+
if (states.contains(MaterialState.hovered)) {
391+
return const Color(0xff00ff00);
392+
}
393+
if (states.contains(MaterialState.focused)) {
394+
return const Color(0xff0000ff);
395+
}
396+
if (states.contains(MaterialState.pressed)) {
397+
return splashColor;
398+
}
399+
return const Color(0xffbadbad); // Shouldn't happen.
400+
}),
401+
onTap: () { },
402+
onLongPress: () { },
403+
onHover: (bool hover) { },
404404
),
405405
),
406406
),
@@ -445,7 +445,187 @@ void main() {
445445
expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff)));
446446
});
447447

448-
testWidgets('InkResponse radius can be updated', (WidgetTester tester) async {
448+
testWidgets('InkWell uses borderRadius for focus highlight', (WidgetTester tester) async {
449+
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
450+
final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus');
451+
await tester.pumpWidget(
452+
Material(
453+
child: Directionality(
454+
textDirection: TextDirection.ltr,
455+
child: Center(
456+
child: SizedBox(
457+
width: 100,
458+
height: 100,
459+
child: InkWell(
460+
focusNode: focusNode,
461+
borderRadius: BorderRadius.circular(10),
462+
focusColor: const Color(0xff0000ff),
463+
onTap: () { },
464+
),
465+
),
466+
),
467+
),
468+
),
469+
);
470+
await tester.pumpAndSettle();
471+
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
472+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 0));
473+
474+
focusNode.requestFocus();
475+
await tester.pumpAndSettle();
476+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1));
477+
478+
expect(inkFeatures, paints..rrect(
479+
rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(10)),
480+
color: const Color(0xff0000ff),
481+
));
482+
});
483+
484+
testWidgets('InkWell uses borderRadius for hover highlight', (WidgetTester tester) async {
485+
await tester.pumpWidget(
486+
Material(
487+
child: Directionality(
488+
textDirection: TextDirection.ltr,
489+
child: Center(
490+
child: SizedBox(
491+
width: 100,
492+
height: 100,
493+
child: MouseRegion(
494+
child: InkWell(
495+
borderRadius: BorderRadius.circular(10),
496+
hoverColor: const Color(0xff00ff00),
497+
onTap: () { },
498+
),
499+
),
500+
),
501+
),
502+
),
503+
),
504+
);
505+
await tester.pumpAndSettle();
506+
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
507+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 0));
508+
509+
// Hover the ink well.
510+
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
511+
await gesture.addPointer(location: tester.getRect(find.byType(InkWell)).center);
512+
await tester.pumpAndSettle();
513+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1));
514+
515+
expect(inkFeatures, paints..rrect(
516+
rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(10)),
517+
color: const Color(0xff00ff00),
518+
));
519+
});
520+
521+
testWidgets('InkWell customBorder clips for focus highlight', (WidgetTester tester) async {
522+
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
523+
final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus');
524+
await tester.pumpWidget(
525+
Material(
526+
child: Directionality(
527+
textDirection: TextDirection.ltr,
528+
child: Align(
529+
alignment: Alignment.topLeft,
530+
child: SizedBox(
531+
width: 100,
532+
height: 100,
533+
child: MouseRegion(
534+
child: InkWell(
535+
focusNode: focusNode,
536+
borderRadius: BorderRadius.circular(10),
537+
customBorder: const CircleBorder(),
538+
hoverColor: const Color(0xff00ff00),
539+
onTap: () { },
540+
),
541+
),
542+
),
543+
),
544+
),
545+
),
546+
);
547+
await tester.pumpAndSettle();
548+
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
549+
expect(inkFeatures, paintsExactlyCountTimes(#clipPath, 0));
550+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 0));
551+
552+
focusNode.requestFocus();
553+
await tester.pumpAndSettle();
554+
expect(inkFeatures, paintsExactlyCountTimes(#clipPath, 1));
555+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1));
556+
557+
// Create a rounded rectangle path with a radius that makes it similar to the custom border circle.
558+
const Rect expectedClipRect = Rect.fromLTRB(0, 0, 100, 100);
559+
final Path expectedClipPath = Path()
560+
..addRRect(RRect.fromRectAndRadius(
561+
expectedClipRect,
562+
const Radius.circular(50.0),
563+
));
564+
// The ink well custom border path should match the rounded rectangle path.
565+
expect(
566+
inkFeatures,
567+
paints..clipPath(pathMatcher: coversSameAreaAs(
568+
expectedClipPath,
569+
areaToCompare: expectedClipRect.inflate(20.0),
570+
sampleSize: 100,
571+
)),
572+
);
573+
});
574+
575+
testWidgets('InkWell customBorder clips for hover highlight', (WidgetTester tester) async {
576+
await tester.pumpWidget(
577+
Material(
578+
child: Directionality(
579+
textDirection: TextDirection.ltr,
580+
child: Align(
581+
alignment: Alignment.topLeft,
582+
child: SizedBox(
583+
width: 100,
584+
height: 100,
585+
child: MouseRegion(
586+
child: InkWell(
587+
borderRadius: BorderRadius.circular(10),
588+
customBorder: const CircleBorder(),
589+
hoverColor: const Color(0xff00ff00),
590+
onTap: () { },
591+
),
592+
),
593+
),
594+
),
595+
),
596+
),
597+
);
598+
await tester.pumpAndSettle();
599+
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures');
600+
expect(inkFeatures, paintsExactlyCountTimes(#clipPath, 0));
601+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 0));
602+
603+
// Hover the ink well.
604+
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
605+
await gesture.addPointer(location: tester.getRect(find.byType(InkWell)).center);
606+
await tester.pumpAndSettle();
607+
expect(inkFeatures, paintsExactlyCountTimes(#clipPath, 1));
608+
expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1));
609+
610+
// Create a rounded rectangle path with a radius that makes it similar to the custom border circle.
611+
const Rect expectedClipRect = Rect.fromLTRB(0, 0, 100, 100);
612+
final Path expectedClipPath = Path()
613+
..addRRect(RRect.fromRectAndRadius(
614+
expectedClipRect,
615+
const Radius.circular(50.0),
616+
));
617+
// The ink well custom border path should match the rounded rectangle path.
618+
expect(
619+
inkFeatures,
620+
paints..clipPath(pathMatcher: coversSameAreaAs(
621+
expectedClipPath,
622+
areaToCompare: expectedClipRect.inflate(20.0),
623+
sampleSize: 100,
624+
)),
625+
);
626+
});
627+
628+
testWidgets('InkResponse radius can be updated', (WidgetTester tester) async {
449629
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
450630
final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus');
451631
Widget boilerplate(double radius) {

0 commit comments

Comments
 (0)