@@ -2552,8 +2552,175 @@ void main() {
2552
2552
expect (scrollStarted, 2 );
2553
2553
expect (scrollEnded, 2 );
2554
2554
});
2555
+
2556
+ testWidgets ('SliverAppBar.medium collapses in NestedScrollView' , (WidgetTester tester) async {
2557
+ final GlobalKey <NestedScrollViewState > nestedScrollView = GlobalKey ();
2558
+ const double collapsedAppBarHeight = 64 ;
2559
+ const double expandedAppBarHeight = 112 ;
2560
+
2561
+ await tester.pumpWidget (MaterialApp (
2562
+ home: Scaffold (
2563
+ body: NestedScrollView (
2564
+ key: nestedScrollView,
2565
+ headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
2566
+ return < Widget > [
2567
+ SliverOverlapAbsorber (
2568
+ handle: NestedScrollView .sliverOverlapAbsorberHandleFor (context),
2569
+ sliver: SliverAppBar .medium (
2570
+ title: const Text ('AppBar Title' ),
2571
+ ),
2572
+ ),
2573
+ ];
2574
+ },
2575
+ body: Builder (
2576
+ builder: (BuildContext context) {
2577
+ return CustomScrollView (
2578
+ slivers: < Widget > [
2579
+ SliverOverlapInjector (handle: NestedScrollView .sliverOverlapAbsorberHandleFor (context)),
2580
+ SliverFixedExtentList (
2581
+ itemExtent: 50.0 ,
2582
+ delegate: SliverChildBuilderDelegate (
2583
+ (BuildContext context, int index) => ListTile (title: Text ('Item $index ' )),
2584
+ childCount: 30 ,
2585
+ ),
2586
+ ),
2587
+ ],
2588
+ );
2589
+ },
2590
+ ),
2591
+ ),
2592
+ ),
2593
+ ));
2594
+
2595
+ // There are two widgets for the title.
2596
+ final Finder expandedTitle = find.text ('AppBar Title' ).last;
2597
+ final Finder expandedTitleClip = find.ancestor (
2598
+ of: expandedTitle,
2599
+ matching: find.byType (ClipRect ),
2600
+ );
2601
+
2602
+ // Default, fully expanded app bar.
2603
+ expect (nestedScrollView.currentState? .outerController.offset, 0 );
2604
+ expect (nestedScrollView.currentState? .innerController.offset, 0 );
2605
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2606
+ expect (appBarHeight (tester), expandedAppBarHeight);
2607
+ expect (tester.getSize (expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
2608
+
2609
+ // Scroll the expanded app bar partially out of view.
2610
+ final Offset point1 = tester.getCenter (find.text ('Item 5' ));
2611
+ await tester.dragFrom (point1, const Offset (0.0 , - 45.0 ));
2612
+ await tester.pump ();
2613
+ expect (nestedScrollView.currentState? .outerController.offset, 45.0 );
2614
+ expect (nestedScrollView.currentState? .innerController.offset, 0.0 );
2615
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2616
+ expect (appBarHeight (tester), expandedAppBarHeight - 45 );
2617
+ expect (tester.getSize (expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight - 45 );
2618
+
2619
+ // Scroll so that it is completely collapsed.
2620
+ await tester.dragFrom (point1, const Offset (0.0 , - 555.0 ));
2621
+ await tester.pump ();
2622
+ expect (nestedScrollView.currentState? .outerController.offset, 48.0 );
2623
+ expect (nestedScrollView.currentState? .innerController.offset, 552.0 );
2624
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2625
+ expect (appBarHeight (tester), collapsedAppBarHeight);
2626
+ expect (tester.getSize (expandedTitleClip).height, 0 );
2627
+
2628
+ // Scroll back to fully expanded.
2629
+ await tester.dragFrom (point1, const Offset (0.0 , 600.0 ));
2630
+ await tester.pump ();
2631
+ expect (nestedScrollView.currentState? .outerController.offset, 0 );
2632
+ expect (nestedScrollView.currentState? .innerController.offset, 0 );
2633
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2634
+ expect (appBarHeight (tester), expandedAppBarHeight);
2635
+ expect (tester.getSize (expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
2636
+ });
2637
+
2638
+ testWidgets ('SliverAppBar.large collapses in NestedScrollView' , (WidgetTester tester) async {
2639
+ final GlobalKey <NestedScrollViewState > nestedScrollView = GlobalKey ();
2640
+ const double collapsedAppBarHeight = 64 ;
2641
+ const double expandedAppBarHeight = 152 ;
2642
+
2643
+ await tester.pumpWidget (MaterialApp (
2644
+ home: Scaffold (
2645
+ body: NestedScrollView (
2646
+ key: nestedScrollView,
2647
+ headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
2648
+ return < Widget > [
2649
+ SliverOverlapAbsorber (
2650
+ handle: NestedScrollView .sliverOverlapAbsorberHandleFor (context),
2651
+ sliver: SliverAppBar .large (
2652
+ title: const Text ('AppBar Title' ),
2653
+ forceElevated: innerBoxIsScrolled,
2654
+ ),
2655
+ ),
2656
+ ];
2657
+ },
2658
+ body: Builder (
2659
+ builder: (BuildContext context) {
2660
+ return CustomScrollView (
2661
+ slivers: < Widget > [
2662
+ SliverOverlapInjector (handle: NestedScrollView .sliverOverlapAbsorberHandleFor (context)),
2663
+ SliverFixedExtentList (
2664
+ itemExtent: 50.0 ,
2665
+ delegate: SliverChildBuilderDelegate (
2666
+ (BuildContext context, int index) => ListTile (title: Text ('Item $index ' )),
2667
+ childCount: 30 ,
2668
+ ),
2669
+ ),
2670
+ ],
2671
+ );
2672
+ },
2673
+ ),
2674
+ ),
2675
+ ),
2676
+ ));
2677
+
2678
+ // There are two widgets for the title.
2679
+ final Finder expandedTitle = find.text ('AppBar Title' ).last;
2680
+ final Finder expandedTitleClip = find.ancestor (
2681
+ of: expandedTitle,
2682
+ matching: find.byType (ClipRect ),
2683
+ );
2684
+
2685
+ // Default, fully expanded app bar.
2686
+ expect (nestedScrollView.currentState? .outerController.offset, 0 );
2687
+ expect (nestedScrollView.currentState? .innerController.offset, 0 );
2688
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2689
+ expect (appBarHeight (tester), expandedAppBarHeight);
2690
+ expect (tester.getSize (expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
2691
+
2692
+ // Scroll the expanded app bar partially out of view.
2693
+ final Offset point1 = tester.getCenter (find.text ('Item 5' ));
2694
+ await tester.dragFrom (point1, const Offset (0.0 , - 45.0 ));
2695
+ await tester.pump ();
2696
+ expect (nestedScrollView.currentState? .outerController.offset, 45.0 );
2697
+ expect (nestedScrollView.currentState? .innerController.offset, 0 );
2698
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2699
+ expect (appBarHeight (tester), expandedAppBarHeight - 45 );
2700
+ expect (tester.getSize (expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight - 45 );
2701
+
2702
+ // Scroll so that it is completely collapsed.
2703
+ await tester.dragFrom (point1, const Offset (0.0 , - 555.0 ));
2704
+ await tester.pump ();
2705
+ expect (nestedScrollView.currentState? .outerController.offset, 88.0 );
2706
+ expect (nestedScrollView.currentState? .innerController.offset, 512.0 );
2707
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2708
+ expect (appBarHeight (tester), collapsedAppBarHeight);
2709
+ expect (tester.getSize (expandedTitleClip).height, 0 );
2710
+
2711
+ // Scroll back to fully expanded.
2712
+ await tester.dragFrom (point1, const Offset (0.0 , 600.0 ));
2713
+ await tester.pump ();
2714
+ expect (nestedScrollView.currentState? .outerController.offset, 0 );
2715
+ expect (nestedScrollView.currentState? .innerController.offset, 0 );
2716
+ expect (find.byType (SliverAppBar ), findsOneWidget);
2717
+ expect (appBarHeight (tester), expandedAppBarHeight);
2718
+ expect (tester.getSize (expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
2719
+ });
2555
2720
}
2556
2721
2722
+ double appBarHeight (WidgetTester tester) => tester.getSize (find.byType (AppBar , skipOffstage: false )).height;
2723
+
2557
2724
class TestHeader extends SliverPersistentHeaderDelegate {
2558
2725
const TestHeader ({ this .key });
2559
2726
final Key ? key;
0 commit comments