@@ -18,19 +18,24 @@ void main() {
1818 ScrollController controller, {
1919 Axis axis = Axis .vertical,
2020 bool reverse = false ,
21+ TextDirection textDirection = TextDirection .ltr,
2122 }) {
2223 final AxisDirection axisDirection;
2324 switch (axis) {
2425 case Axis .horizontal:
25- axisDirection = reverse ? AxisDirection .left : AxisDirection .right;
26+ if (textDirection == TextDirection .rtl) {
27+ axisDirection = reverse ? AxisDirection .right : AxisDirection .left;
28+ } else {
29+ axisDirection = reverse ? AxisDirection .left : AxisDirection .right;
30+ }
2631 break ;
2732 case Axis .vertical:
2833 axisDirection = reverse ? AxisDirection .up : AxisDirection .down;
2934 break ;
3035 }
3136
3237 return Directionality (
33- textDirection: TextDirection .ltr ,
38+ textDirection: textDirection ,
3439 child: MediaQuery (
3540 data: const MediaQueryData (size: Size (800.0 , 600.0 )),
3641 child: ScrollConfiguration (
@@ -218,6 +223,92 @@ void main() {
218223 );
219224 });
220225
226+ testWidgets ('Stretch overscroll works in reverse - horizontal - RTL' , (WidgetTester tester) async {
227+ final GlobalKey box1Key = GlobalKey ();
228+ final GlobalKey box2Key = GlobalKey ();
229+ final GlobalKey box3Key = GlobalKey ();
230+ final ScrollController controller = ScrollController ();
231+ await tester.pumpWidget (
232+ buildTest (
233+ box1Key,
234+ box2Key,
235+ box3Key,
236+ controller,
237+ axis: Axis .horizontal,
238+ reverse: true ,
239+ textDirection: TextDirection .rtl,
240+ )
241+ );
242+
243+ expect (find.byType (StretchingOverscrollIndicator ), findsOneWidget);
244+ expect (find.byType (GlowingOverscrollIndicator ), findsNothing);
245+ final RenderBox box1 = tester.renderObject (find.byKey (box1Key));
246+ final RenderBox box2 = tester.renderObject (find.byKey (box2Key));
247+ final RenderBox box3 = tester.renderObject (find.byKey (box3Key));
248+
249+ expect (controller.offset, 0.0 );
250+ expect (box1.localToGlobal (Offset .zero), Offset .zero);
251+ expect (box2.localToGlobal (Offset .zero), const Offset (300.0 , 0.0 ));
252+ expect (box3.localToGlobal (Offset .zero), const Offset (600.0 , 0.0 ));
253+ await expectLater (
254+ find.byType (CustomScrollView ),
255+ matchesGoldenFile ('overscroll_stretch.horizontal.reverse.rtl.start.png' ),
256+ );
257+
258+ TestGesture gesture = await tester.startGesture (tester.getCenter (find.byType (CustomScrollView )));
259+ // Overscroll the start
260+ await gesture.moveBy (const Offset (200.0 , 0.0 ));
261+ await tester.pumpAndSettle ();
262+
263+ expect (box1.localToGlobal (Offset .zero), Offset .zero);
264+ expect (box2.localToGlobal (Offset .zero).dx, greaterThan (305.0 ));
265+ expect (box3.localToGlobal (Offset .zero).dx, greaterThan (610.0 ));
266+ await expectLater (
267+ find.byType (CustomScrollView ),
268+ matchesGoldenFile ('overscroll_stretch.horizontal.reverse.rtl.start.stretched.png' ),
269+ );
270+
271+ await gesture.up ();
272+ await tester.pumpAndSettle ();
273+
274+ // Stretch released back to the start
275+ expect (box1.localToGlobal (Offset .zero), Offset .zero);
276+ expect (box2.localToGlobal (Offset .zero), const Offset (300.0 , 0.0 ));
277+ expect (box3.localToGlobal (Offset .zero), const Offset (600.0 , 0.0 ));
278+
279+ // Jump to end of the list
280+ controller.jumpTo (controller.position.maxScrollExtent);
281+ await tester.pumpAndSettle ();
282+ expect (controller.offset, 100.0 );
283+ expect (box1.localToGlobal (Offset .zero).dx, - 100.0 );
284+ expect (box2.localToGlobal (Offset .zero).dx, 200.0 );
285+ expect (box3.localToGlobal (Offset .zero).dx, 500.0 );
286+ await expectLater (
287+ find.byType (CustomScrollView ),
288+ matchesGoldenFile ('overscroll_stretch.horizontal.reverse.rtl.end.png' ),
289+ );
290+
291+ gesture = await tester.startGesture (tester.getCenter (find.byType (CustomScrollView )));
292+ // Overscroll the end
293+ await gesture.moveBy (const Offset (- 200.0 , 0.0 ));
294+ await tester.pumpAndSettle ();
295+ expect (box1.localToGlobal (Offset .zero).dx, lessThan (- 116.0 ));
296+ expect (box2.localToGlobal (Offset .zero).dx, lessThan (190.0 ));
297+ expect (box3.localToGlobal (Offset .zero).dx, lessThan (500.0 ));
298+ await expectLater (
299+ find.byType (CustomScrollView ),
300+ matchesGoldenFile ('overscroll_stretch.horizontal.reverse.rtl.end.stretched.png' ),
301+ );
302+
303+ await gesture.up ();
304+ await tester.pumpAndSettle ();
305+
306+ // Stretch released back
307+ expect (box1.localToGlobal (Offset .zero).dx, - 100.0 );
308+ expect (box2.localToGlobal (Offset .zero).dx, 200.0 );
309+ expect (box3.localToGlobal (Offset .zero).dx, 500.0 );
310+ });
311+
221312 testWidgets ('Stretch overscroll horizontally' , (WidgetTester tester) async {
222313 final GlobalKey box1Key = GlobalKey ();
223314 final GlobalKey box2Key = GlobalKey ();
@@ -295,6 +386,46 @@ void main() {
295386 expect (box3.localToGlobal (Offset .zero).dx, 500.0 );
296387 });
297388
389+ testWidgets ('Stretch overscroll horizontally RTl' , (WidgetTester tester) async {
390+ final GlobalKey box1Key = GlobalKey ();
391+ final GlobalKey box2Key = GlobalKey ();
392+ final GlobalKey box3Key = GlobalKey ();
393+ final ScrollController controller = ScrollController ();
394+ await tester.pumpWidget (
395+ buildTest (
396+ box1Key,
397+ box2Key,
398+ box3Key,
399+ controller,
400+ axis: Axis .horizontal,
401+ textDirection: TextDirection .rtl,
402+ )
403+ );
404+
405+ expect (find.byType (StretchingOverscrollIndicator ), findsOneWidget);
406+ expect (find.byType (GlowingOverscrollIndicator ), findsNothing);
407+ final RenderBox box1 = tester.renderObject (find.byKey (box1Key));
408+ final RenderBox box2 = tester.renderObject (find.byKey (box2Key));
409+ final RenderBox box3 = tester.renderObject (find.byKey (box3Key));
410+
411+ expect (controller.offset, 0.0 );
412+ expect (box1.localToGlobal (Offset .zero), const Offset (500.0 , 0.0 ));
413+ expect (box2.localToGlobal (Offset .zero), const Offset (200.0 , 0.0 ));
414+ expect (box3.localToGlobal (Offset .zero), const Offset (- 100.0 , 0.0 ));
415+
416+ final TestGesture gesture = await tester.startGesture (tester.getCenter (find.byType (CustomScrollView )));
417+ // Overscroll
418+ await gesture.moveBy (const Offset (- 200.0 , 0.0 ));
419+ await tester.pumpAndSettle ();
420+ expect (box1.localToGlobal (Offset .zero).dx, lessThan (500.0 ));
421+ expect (box2.localToGlobal (Offset .zero).dx, lessThan (200.0 ));
422+ expect (box3.localToGlobal (Offset .zero).dx, lessThan (- 100.0 ));
423+ await expectLater (
424+ find.byType (CustomScrollView ),
425+ matchesGoldenFile ('overscroll_stretch.horizontal.rtl.png' ),
426+ );
427+ });
428+
298429 testWidgets ('Disallow stretching overscroll' , (WidgetTester tester) async {
299430 final GlobalKey box1Key = GlobalKey ();
300431 final GlobalKey box2Key = GlobalKey ();
0 commit comments