From ff347bfde5520e8ba3d49f4f42a596fda8698ded Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 21 Dec 2022 23:18:00 +0200 Subject: [PATCH] Fix `InkRipple` doesn't respect `rectCallback` when rendering ink circle (#117395) --- .../flutter/lib/src/material/ink_ripple.dart | 6 +- .../flutter/test/material/ink_paint_test.dart | 86 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/ink_ripple.dart b/packages/flutter/lib/src/material/ink_ripple.dart index c1dc3e015040..4da6267f23d5 100644 --- a/packages/flutter/lib/src/material/ink_ripple.dart +++ b/packages/flutter/lib/src/material/ink_ripple.dart @@ -232,10 +232,14 @@ class InkRipple extends InteractiveInkFeature { void paintFeature(Canvas canvas, Matrix4 transform) { final int alpha = _fadeInController.isAnimating ? _fadeIn.value : _fadeOut.value; final Paint paint = Paint()..color = color.withAlpha(alpha); + Rect? rect; + if (_clipCallback != null) { + rect = _clipCallback!(); + } // Splash moves to the center of the reference box. final Offset center = Offset.lerp( _position, - referenceBox.size.center(Offset.zero), + rect != null ? rect.center : referenceBox.size.center(Offset.zero), Curves.ease.transform(_radiusController.value), )!; paintInkCircle( diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index a574fcead68c..b119cb70bbb3 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -445,4 +445,90 @@ void main() { throw 'Expected: paint.color.alpha == 0, found: ${paint.color.alpha}'; })); }); + + testWidgets('Custom rectCallback renders an ink splash from its center', (WidgetTester tester) async { + const Color splashColor = Color(0xff00ff00); + + Widget buildWidget({InteractiveInkFeatureFactory? splashFactory}) { + return Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: Center( + child: SizedBox( + width: 100.0, + height: 200.0, + child: InkResponse( + splashColor: splashColor, + containedInkWell: true, + highlightShape: BoxShape.rectangle, + splashFactory: splashFactory, + onTap: () { }, + ), + ), + ), + ), + ); + } + + await tester.pumpWidget(buildWidget()); + + final Offset center = tester.getCenter(find.byType(SizedBox)); + TestGesture gesture = await tester.startGesture(center); + await tester.pump(); // start gesture + await tester.pumpAndSettle(); // Finish rendering ink splash. + + RenderBox box = Material.of(tester.element(find.byType(InkResponse))) as RenderBox; + expect( + box, + paints + ..circle(x: 50.0, y: 100.0, color: splashColor) + ); + + await gesture.up(); + + await tester.pumpWidget(buildWidget(splashFactory: _InkRippleFactory())); + await tester.pumpAndSettle(); // Finish rendering ink splash. + + gesture = await tester.startGesture(center); + await tester.pump(); // start gesture + await tester.pumpAndSettle(); // Finish rendering ink splash. + + box = Material.of(tester.element(find.byType(InkResponse))) as RenderBox; + expect( + box, + paints + ..circle(x: 50.0, y: 50.0, color: splashColor) + ); + }); +} + +class _InkRippleFactory extends InteractiveInkFeatureFactory { + @override + InteractiveInkFeature create({ + required MaterialInkController controller, + required RenderBox referenceBox, + required Offset position, + required Color color, + required TextDirection textDirection, + bool containedInkWell = false, + RectCallback? rectCallback, + BorderRadius? borderRadius, + ShapeBorder? customBorder, + double? radius, + VoidCallback? onRemoved, + }) { + return InkRipple( + controller: controller, + referenceBox: referenceBox, + position: position, + color: color, + containedInkWell: containedInkWell, + rectCallback: () => Offset.zero & const Size(100, 100), + borderRadius: borderRadius, + customBorder: customBorder, + radius: radius, + onRemoved: onRemoved, + textDirection: textDirection, + ); + } }