slivers_protocol_test.dart 3.64 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' as math;

import 'package:flutter/rendering.dart';
8
import 'package:flutter/widgets.dart';
9
import 'package:flutter_test/flutter_test.dart';
10 11

void verifyPaintPosition(GlobalKey key, Offset ideal) {
12
  final RenderObject target = key.currentContext!.findRenderObject()!;
Dan Field's avatar
Dan Field committed
13
  expect(target.parent, isA<RenderViewport>());
14
  final SliverPhysicalParentData parentData = target.parentData! as SliverPhysicalParentData;
15
  final Offset actual = parentData.paintOffset;
16 17 18 19 20 21 22
  expect(actual, ideal);
}

void main() {
  testWidgets('Sliver protocol', (WidgetTester tester) async {
    GlobalKey key1, key2, key3, key4, key5;
    await tester.pumpWidget(
23
      Directionality(
24
        textDirection: TextDirection.ltr,
25
        child: CustomScrollView(
26
          slivers: <Widget>[
27 28 29 30 31
            BigSliver(key: key1 = GlobalKey()),
            OverlappingSliver(key: key2 = GlobalKey()),
            OverlappingSliver(key: key3 = GlobalKey()),
            BigSliver(key: key4 = GlobalKey()),
            BigSliver(key: key5 = GlobalKey()),
32 33
          ],
        ),
34 35
      ),
    );
36
    final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position;
37
    const double max = RenderBigSliver.height * 3.0 + (RenderOverlappingSliver.totalHeight) * 2.0 - 600.0; // 600 is the height of the test viewport
38 39 40 41 42
    assert(max < 10000.0);
    expect(max, 1450.0);
    expect(position.pixels, 0.0);
    expect(position.minScrollExtent, 0.0);
    expect(position.maxScrollExtent, max);
43
    position.animateTo(10000.0, curve: Curves.linear, duration: const Duration(minutes: 1));
44
    await tester.pumpAndSettle(const Duration(milliseconds: 10));
45 46 47
    expect(position.pixels, max);
    expect(position.minScrollExtent, 0.0);
    expect(position.maxScrollExtent, max);
48 49 50 51
    verifyPaintPosition(key1, Offset.zero);
    verifyPaintPosition(key2, Offset.zero);
    verifyPaintPosition(key3, Offset.zero);
    verifyPaintPosition(key4, Offset.zero);
52
    verifyPaintPosition(key5, const Offset(0.0, 50.0));
53 54 55 56 57
  });
}

class RenderBigSliver extends RenderSliver {
  static const double height = 550.0;
58
  double get paintExtent => (height - constraints.scrollOffset).clamp(0.0, constraints.remainingPaintExtent);
59 60 61

  @override
  void performLayout() {
62
    geometry = SliverGeometry(
63 64 65 66 67 68 69 70
      scrollExtent: height,
      paintExtent: paintExtent,
      maxPaintExtent: height,
    );
  }
}

class BigSliver extends LeafRenderObjectWidget {
71
  const BigSliver({ Key? key }) : super(key: key);
72 73
  @override
  RenderBigSliver createRenderObject(BuildContext context) {
74
    return RenderBigSliver();
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
  }
}

class RenderOverlappingSliver extends RenderSliver {
  static const double totalHeight = 200.0;
  static const double fixedHeight = 100.0;

  double get paintExtent {
    return math.min(
             math.max(
               fixedHeight,
               totalHeight - constraints.scrollOffset,
             ),
             constraints.remainingPaintExtent,
           );
  }

  double get layoutExtent {
93
    return (totalHeight - constraints.scrollOffset).clamp(0.0, constraints.remainingPaintExtent);
94 95 96 97
  }

  @override
  void performLayout() {
98
    geometry = SliverGeometry(
99 100 101 102 103 104 105 106 107
      scrollExtent: totalHeight,
      paintExtent: paintExtent,
      layoutExtent: layoutExtent,
      maxPaintExtent: totalHeight,
    );
  }
}

class OverlappingSliver extends LeafRenderObjectWidget {
108
  const OverlappingSliver({ Key? key }) : super(key: key);
109 110
  @override
  RenderOverlappingSliver createRenderObject(BuildContext context) {
111
    return RenderOverlappingSliver();
112 113
  }
}