Skip to content

Commit 1d03459

Browse files
authored
Fix getOffsetToReveal for growthDirection reversed and AxisDirection down or right (flutter#38441)
* Take growth direction into account when computing value for getOffsetForReveal in AxisDirection.right and .up conditions. * Add alignment 1.0 test to left - reverse growth * Add Reverse List showOnScreen test * Formatting fix.
1 parent f1003d5 commit 1d03459

File tree

2 files changed

+186
-2
lines changed

2 files changed

+186
-2
lines changed

packages/flutter/lib/src/rendering/viewport.dart

+20-2
Original file line numberDiff line numberDiff line change
@@ -649,11 +649,29 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
649649
targetMainAxisExtent = bounds.height;
650650
break;
651651
case AxisDirection.right:
652-
leadingScrollOffset += bounds.left;
652+
double offset;
653+
switch (growthDirection) {
654+
case GrowthDirection.forward:
655+
offset = bounds.left;
656+
break;
657+
case GrowthDirection.reverse:
658+
offset = bounds.right;
659+
break;
660+
}
661+
leadingScrollOffset += offset;
653662
targetMainAxisExtent = bounds.width;
654663
break;
655664
case AxisDirection.down:
656-
leadingScrollOffset += bounds.top;
665+
double offset;
666+
switch (growthDirection) {
667+
case GrowthDirection.forward:
668+
offset = bounds.top;
669+
break;
670+
case GrowthDirection.reverse:
671+
offset = bounds.bottom;
672+
break;
673+
}
674+
leadingScrollOffset += offset;
657675
targetMainAxisExtent = bounds.height;
658676
break;
659677
case AxisDirection.left:

packages/flutter/test/rendering/viewport_test.dart

+166
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,107 @@ void main() {
314314
expect(revealed.offset, 5 * (100 + 22 + 22) + 22 - 100);
315315
});
316316

317+
testWidgets('Viewport getOffsetToReveal Sliver - up - reverse growth', (WidgetTester tester) async {
318+
const Key centerKey = ValueKey<String>('center');
319+
final Widget centerSliver = SliverPadding(
320+
key: centerKey,
321+
padding: const EdgeInsets.all(22.0),
322+
sliver: SliverToBoxAdapter(
323+
child: Container(
324+
height: 100.0,
325+
child: const Text('Tile center'),
326+
),
327+
),
328+
);
329+
final Widget lowerItem = Container(
330+
height: 100.0,
331+
child: const Text('Tile lower'),
332+
);
333+
final Widget lowerSliver = SliverPadding(
334+
padding: const EdgeInsets.all(22.0),
335+
sliver: SliverToBoxAdapter(
336+
child: lowerItem,
337+
),
338+
);
339+
340+
await tester.pumpWidget(
341+
Directionality(
342+
textDirection: TextDirection.ltr,
343+
child: Center(
344+
child: Container(
345+
height: 200.0,
346+
width: 300.0,
347+
child: CustomScrollView(
348+
center: centerKey,
349+
reverse: true,
350+
slivers: <Widget>[lowerSliver, centerSliver],
351+
),
352+
),
353+
),
354+
),
355+
);
356+
357+
final RenderAbstractViewport viewport = tester.allRenderObjects.firstWhere((RenderObject r) => r is RenderAbstractViewport);
358+
359+
final RenderObject target = tester.renderObject(find.byWidget(lowerItem, skipOffstage: false));
360+
RevealedOffset revealed = viewport.getOffsetToReveal(target, 0.0);
361+
expect(revealed.offset, - 100 - 22);
362+
363+
revealed = viewport.getOffsetToReveal(target, 1.0);
364+
expect(revealed.offset, - 100 - 22 - 100);
365+
});
366+
367+
testWidgets('Viewport getOffsetToReveal Sliver - left - reverse growth', (WidgetTester tester) async {
368+
const Key centerKey = ValueKey<String>('center');
369+
final Widget centerSliver = SliverPadding(
370+
key: centerKey,
371+
padding: const EdgeInsets.all(22.0),
372+
sliver: SliverToBoxAdapter(
373+
child: Container(
374+
width: 100.0,
375+
child: const Text('Tile center'),
376+
),
377+
),
378+
);
379+
final Widget lowerItem = Container(
380+
width: 100.0,
381+
child: const Text('Tile lower'),
382+
);
383+
final Widget lowerSliver = SliverPadding(
384+
padding: const EdgeInsets.all(22.0),
385+
sliver: SliverToBoxAdapter(
386+
child: lowerItem,
387+
),
388+
);
389+
390+
await tester.pumpWidget(
391+
Directionality(
392+
textDirection: TextDirection.ltr,
393+
child: Center(
394+
child: Container(
395+
height: 200.0,
396+
width: 300.0,
397+
child: CustomScrollView(
398+
scrollDirection: Axis.horizontal,
399+
center: centerKey,
400+
reverse: true,
401+
slivers: <Widget>[lowerSliver, centerSliver],
402+
),
403+
),
404+
),
405+
),
406+
);
407+
408+
final RenderAbstractViewport viewport = tester.allRenderObjects.firstWhere((RenderObject r) => r is RenderAbstractViewport);
409+
410+
final RenderObject target = tester.renderObject(find.byWidget(lowerItem, skipOffstage: false));
411+
RevealedOffset revealed = viewport.getOffsetToReveal(target, 0.0);
412+
expect(revealed.offset, -100 - 22);
413+
414+
revealed = viewport.getOffsetToReveal(target, 1.0);
415+
expect(revealed.offset, - 100 - 22 - 200);
416+
});
417+
317418
testWidgets('Viewport getOffsetToReveal Sliver - left', (WidgetTester tester) async {
318419
final List<Widget> children = <Widget>[];
319420
await tester.pumpWidget(
@@ -556,6 +657,71 @@ void main() {
556657
);
557658
}
558659

660+
testWidgets('Reverse List showOnScreen', (WidgetTester tester) async {
661+
const double screenHeight = 400.0;
662+
const double screenWidth = 400.0;
663+
const double itemHeight = screenHeight / 10.0;
664+
const ValueKey<String> centerKey = ValueKey<String>('center');
665+
666+
tester.binding.window.devicePixelRatioTestValue = 1.0;
667+
tester.binding.window.physicalSizeTestValue = const Size(screenWidth, screenHeight);
668+
669+
await tester.pumpWidget(Directionality(
670+
textDirection: TextDirection.ltr,
671+
child: CustomScrollView(
672+
center: centerKey,
673+
reverse: true,
674+
slivers: <Widget>[
675+
SliverList(
676+
delegate: SliverChildListDelegate(
677+
List<Widget>.generate(
678+
10,
679+
(int index) => SizedBox(
680+
height: itemHeight,
681+
child: Text('Item ${-index - 1}'),
682+
),
683+
),
684+
),
685+
),
686+
SliverList(
687+
key: centerKey,
688+
delegate: SliverChildListDelegate(
689+
List<Widget>.generate(
690+
1,
691+
(int index) => const SizedBox(
692+
height: itemHeight,
693+
child: Text('Item 0'),
694+
),
695+
),
696+
),
697+
),
698+
SliverList(
699+
delegate: SliverChildListDelegate(
700+
List<Widget>.generate(
701+
10,
702+
(int index) => SizedBox(
703+
height: itemHeight,
704+
child: Text('Item ${index + 1}'),
705+
),
706+
),
707+
),
708+
),
709+
],
710+
),
711+
),
712+
);
713+
714+
expect(find.text('Item -1'), findsNothing);
715+
716+
final RenderBox itemNeg1 =
717+
tester.renderObject(find.text('Item -1', skipOffstage: false));
718+
719+
itemNeg1.showOnScreen(duration: const Duration(seconds: 1));
720+
await tester.pumpAndSettle();
721+
722+
expect(find.text('Item -1'), findsOneWidget);
723+
});
724+
559725
testWidgets('in view in inner, but not in outer', (WidgetTester tester) async {
560726
final ScrollController inner = ScrollController();
561727
final ScrollController outer = ScrollController();

0 commit comments

Comments
 (0)