[framework] use ImageFilter for stretch overscroll. (#133613)

Rather than changing the size of the child elements (relaying out text
and potentially changing glyph shape and position due to pixel
snapping), apply the stretch effect as a compositing effect - render the
children to a texture and stretch the texture. If we end up using an
image shader to apply an custom shader we'll need to do this anyway.

Fixes https://github.com/flutter/flutter/issues/129528

### Before


https://github.com/flutter/flutter/assets/8975114/16e9eb57-f864-4093-b4a4-461082b89b43

### After


https://github.com/flutter/flutter/assets/8975114/14cf0167-8922-4876-a325-e3bc154b084f
This commit is contained in:
Jonah Williams 2023-08-30 18:58:42 -07:00 committed by GitHub
parent 5296f8468f
commit a0862f1c3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 1 deletions

View File

@ -786,10 +786,10 @@ class _StretchingOverscrollIndicatorState extends State<StretchingOverscrollIndi
);
final double viewportDimension = _lastOverscrollNotification?.metrics.viewportDimension ?? mainAxisSize;
final Widget transform = Transform(
alignment: alignment,
transform: Matrix4.diagonal3Values(x, y, 1.0),
filterQuality: stretch == 0 ? null : FilterQuality.low,
child: widget.child,
);

View File

@ -1124,4 +1124,29 @@ void main() {
await gesture.up();
});
testWidgets('Stretch overscroll only uses image filter during stretch effect', (WidgetTester tester) async {
final GlobalKey box1Key = GlobalKey();
final GlobalKey box2Key = GlobalKey();
final GlobalKey box3Key = GlobalKey();
final ScrollController controller = ScrollController();
await tester.pumpWidget(
buildTest(
box1Key,
box2Key,
box3Key,
controller,
axis: Axis.horizontal,
)
);
expect(tester.layers, isNot(contains(isA<ImageFilterLayer>())));
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CustomScrollView)));
// Overscroll
await gesture.moveBy(const Offset(200.0, 0.0));
await tester.pumpAndSettle();
expect(tester.layers, contains(isA<ImageFilterLayer>()));
});
}