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

5
import 'package:flutter/material.dart';
Ian Hickson's avatar
Ian Hickson committed
6
import 'package:flutter/rendering.dart';
7
import 'package:flutter_test/flutter_test.dart';
Ian Hickson's avatar
Ian Hickson committed
8

9 10 11 12 13 14 15 16 17 18 19 20
class _MockRenderSliver extends RenderSliver {
  @override
  void performLayout() {
    geometry = const SliverGeometry(
      paintOrigin: 10,
      paintExtent: 10,
      maxPaintExtent: 10,
    );
  }

}

21
Future<void> test(WidgetTester tester, double offset, EdgeInsetsGeometry padding, AxisDirection axisDirection, TextDirection textDirection) {
22
  return tester.pumpWidget(
23
    Directionality(
24
      textDirection: textDirection,
25 26
      child: Viewport(
        offset: ViewportOffset.fixed(offset),
27 28
        axisDirection: axisDirection,
        slivers: <Widget>[
29
          const SliverToBoxAdapter(child: SizedBox(width: 400.0, height: 400.0, child: Text('before'))),
30
          SliverPadding(
31
            padding: padding,
32
            sliver: const SliverToBoxAdapter(child: SizedBox(width: 400.0, height: 400.0, child: Text('padded'))),
33
          ),
34
          const SliverToBoxAdapter(child: SizedBox(width: 400.0, height: 400.0, child: Text('after'))),
35
        ],
Ian Hickson's avatar
Ian Hickson committed
36
      ),
37
    ),
38
  );
Ian Hickson's avatar
Ian Hickson committed
39 40 41
}

void verify(WidgetTester tester, List<Rect> answerKey) {
42
  final List<Rect> testAnswers = tester.renderObjectList<RenderBox>(find.byType(SizedBox, skipOffstage: false)).map<Rect>(
Ian Hickson's avatar
Ian Hickson committed
43
    (RenderBox target) {
44 45
      final Offset topLeft = target.localToGlobal(Offset.zero);
      final Offset bottomRight = target.localToGlobal(target.size.bottomRight(Offset.zero));
46
      return Rect.fromPoints(topLeft, bottomRight);
47
    },
Ian Hickson's avatar
Ian Hickson committed
48 49 50 51 52
  ).toList();
  expect(testAnswers, equals(answerKey));
}

void main() {
53
  testWidgets('Viewport+SliverPadding basic test (VISUAL)', (WidgetTester tester) async {
54
    const EdgeInsets padding = EdgeInsets.fromLTRB(25.0, 20.0, 15.0, 35.0);
55
    await test(tester, 0.0, padding, AxisDirection.down, TextDirection.ltr);
Adam Barth's avatar
Adam Barth committed
56
    expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
Ian Hickson's avatar
Ian Hickson committed
57
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
58 59 60
      const Rect.fromLTWH(0.0, 0.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, 420.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 855.0, 800.0, 400.0),
Ian Hickson's avatar
Ian Hickson committed
61 62
    ]);

63
    await test(tester, 200.0, padding, AxisDirection.down, TextDirection.ltr);
Ian Hickson's avatar
Ian Hickson committed
64
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
65 66 67
      const Rect.fromLTWH(0.0, -200.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, 220.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 655.0, 800.0, 400.0),
Ian Hickson's avatar
Ian Hickson committed
68 69
    ]);

70
    await test(tester, 390.0, padding, AxisDirection.down, TextDirection.ltr);
Ian Hickson's avatar
Ian Hickson committed
71
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
72 73 74
      const Rect.fromLTWH(0.0, -390.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, 30.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 465.0, 800.0, 400.0),
Ian Hickson's avatar
Ian Hickson committed
75 76
    ]);

77
    await test(tester, 490.0, padding, AxisDirection.down, TextDirection.ltr);
Ian Hickson's avatar
Ian Hickson committed
78
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
79 80 81
      const Rect.fromLTWH(0.0, -490.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, -70.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 365.0, 800.0, 400.0),
Ian Hickson's avatar
Ian Hickson committed
82 83
    ]);

84
    await test(tester, 10000.0, padding, AxisDirection.down, TextDirection.ltr);
Ian Hickson's avatar
Ian Hickson committed
85
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
86 87 88
      const Rect.fromLTWH(0.0, -10000.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, -9580.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, -9145.0, 800.0, 400.0),
Ian Hickson's avatar
Ian Hickson committed
89 90 91
    ]);
  });

92
  testWidgets('Viewport+SliverPadding basic test (LTR)', (WidgetTester tester) async {
93
    const EdgeInsetsDirectional padding = EdgeInsetsDirectional.fromSTEB(25.0, 20.0, 15.0, 35.0);
94
    await test(tester, 0.0, padding, AxisDirection.down, TextDirection.ltr);
95 96
    expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
97 98 99
      const Rect.fromLTWH(0.0, 0.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, 420.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 855.0, 800.0, 400.0),
100 101
    ]);

102
    await test(tester, 200.0, padding, AxisDirection.down, TextDirection.ltr);
103
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
104 105 106
      const Rect.fromLTWH(0.0, -200.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, 220.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 655.0, 800.0, 400.0),
107 108
    ]);

109
    await test(tester, 390.0, padding, AxisDirection.down, TextDirection.ltr);
110
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
111 112 113
      const Rect.fromLTWH(0.0, -390.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, 30.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 465.0, 800.0, 400.0),
114 115
    ]);

116
    await test(tester, 490.0, padding, AxisDirection.down, TextDirection.ltr);
117
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
118 119 120
      const Rect.fromLTWH(0.0, -490.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, -70.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 365.0, 800.0, 400.0),
121 122
    ]);

123
    await test(tester, 10000.0, padding, AxisDirection.down, TextDirection.ltr);
124
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
125 126 127
      const Rect.fromLTWH(0.0, -10000.0, 800.0, 400.0),
      const Rect.fromLTWH(25.0, -9580.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, -9145.0, 800.0, 400.0),
128 129 130 131
    ]);
  });

  testWidgets('Viewport+SliverPadding basic test (RTL)', (WidgetTester tester) async {
132
    const EdgeInsetsDirectional padding = EdgeInsetsDirectional.fromSTEB(25.0, 20.0, 15.0, 35.0);
133
    await test(tester, 0.0, padding, AxisDirection.down, TextDirection.rtl);
134 135
    expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
136 137 138
      const Rect.fromLTWH(0.0, 0.0, 800.0, 400.0),
      const Rect.fromLTWH(15.0, 420.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 855.0, 800.0, 400.0),
139 140
    ]);

141
    await test(tester, 200.0, padding, AxisDirection.down, TextDirection.rtl);
142
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
143 144 145
      const Rect.fromLTWH(0.0, -200.0, 800.0, 400.0),
      const Rect.fromLTWH(15.0, 220.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 655.0, 800.0, 400.0),
146 147
    ]);

148
    await test(tester, 390.0, padding, AxisDirection.down, TextDirection.rtl);
149
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
150 151 152
      const Rect.fromLTWH(0.0, -390.0, 800.0, 400.0),
      const Rect.fromLTWH(15.0, 30.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 465.0, 800.0, 400.0),
153 154
    ]);

155
    await test(tester, 490.0, padding, AxisDirection.down, TextDirection.rtl);
156
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
157 158 159
      const Rect.fromLTWH(0.0, -490.0, 800.0, 400.0),
      const Rect.fromLTWH(15.0, -70.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, 365.0, 800.0, 400.0),
160 161
    ]);

162
    await test(tester, 10000.0, padding, AxisDirection.down, TextDirection.rtl);
163
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
164 165 166
      const Rect.fromLTWH(0.0, -10000.0, 800.0, 400.0),
      const Rect.fromLTWH(15.0, -9580.0, 760.0, 400.0),
      const Rect.fromLTWH(0.0, -9145.0, 800.0, 400.0),
167 168 169
    ]);
  });

Adam Barth's avatar
Adam Barth committed
170
  testWidgets('Viewport+SliverPadding hit testing', (WidgetTester tester) async {
171
    const EdgeInsets padding = EdgeInsets.all(30.0);
172
    await test(tester, 350.0, padding, AxisDirection.down, TextDirection.ltr);
Adam Barth's avatar
Adam Barth committed
173
    expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
Ian Hickson's avatar
Ian Hickson committed
174
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
175 176 177
      const Rect.fromLTWH(0.0, -350.0, 800.0, 400.0),
      const Rect.fromLTWH(30.0, 80.0, 740.0, 400.0),
      const Rect.fromLTWH(0.0, 510.0, 800.0, 400.0),
Ian Hickson's avatar
Ian Hickson committed
178 179
    ]);
    HitTestResult result;
180
    result = tester.hitTestOnBinding(const Offset(10.0, 10.0));
181
    expectIsTextSpan(result.path.first.target, 'before');
182
    result = tester.hitTestOnBinding(const Offset(10.0, 60.0));
Dan Field's avatar
Dan Field committed
183
    expect(result.path.first.target, isA<RenderView>());
184
    result = tester.hitTestOnBinding(const Offset(100.0, 100.0));
185
    expectIsTextSpan(result.path.first.target, 'padded');
186
    result = tester.hitTestOnBinding(const Offset(100.0, 490.0));
Dan Field's avatar
Dan Field committed
187
    expect(result.path.first.target, isA<RenderView>());
188
    result = tester.hitTestOnBinding(const Offset(10.0, 520.0));
189
    expectIsTextSpan(result.path.first.target, 'after');
Ian Hickson's avatar
Ian Hickson committed
190 191
  });

Adam Barth's avatar
Adam Barth committed
192
  testWidgets('Viewport+SliverPadding hit testing up', (WidgetTester tester) async {
193
    const EdgeInsets padding = EdgeInsets.all(30.0);
194
    await test(tester, 350.0, padding, AxisDirection.up, TextDirection.ltr);
Adam Barth's avatar
Adam Barth committed
195
    expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
Ian Hickson's avatar
Ian Hickson committed
196
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
197 198 199
      const Rect.fromLTWH(0.0, 600.0+350.0-400.0, 800.0, 400.0),
      const Rect.fromLTWH(30.0, 600.0-80.0-400.0, 740.0, 400.0),
      const Rect.fromLTWH(0.0, 600.0-510.0-400.0, 800.0, 400.0),
Ian Hickson's avatar
Ian Hickson committed
200 201
    ]);
    HitTestResult result;
202
    result = tester.hitTestOnBinding(const Offset(10.0, 600.0-10.0));
203
    expectIsTextSpan(result.path.first.target, 'before');
204
    result = tester.hitTestOnBinding(const Offset(10.0, 600.0-60.0));
Dan Field's avatar
Dan Field committed
205
    expect(result.path.first.target, isA<RenderView>());
206
    result = tester.hitTestOnBinding(const Offset(100.0, 600.0-100.0));
207
    expectIsTextSpan(result.path.first.target, 'padded');
208
    result = tester.hitTestOnBinding(const Offset(100.0, 600.0-490.0));
Dan Field's avatar
Dan Field committed
209
    expect(result.path.first.target, isA<RenderView>());
210
    result = tester.hitTestOnBinding(const Offset(10.0, 600.0-520.0));
211
    expectIsTextSpan(result.path.first.target, 'after');
Ian Hickson's avatar
Ian Hickson committed
212 213
  });

Adam Barth's avatar
Adam Barth committed
214
  testWidgets('Viewport+SliverPadding hit testing left', (WidgetTester tester) async {
215
    const EdgeInsets padding = EdgeInsets.all(30.0);
216
    await test(tester, 350.0, padding, AxisDirection.left, TextDirection.ltr);
Adam Barth's avatar
Adam Barth committed
217
    expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
Ian Hickson's avatar
Ian Hickson committed
218
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
219 220 221
      const Rect.fromLTWH(800.0+350.0-400.0, 0.0, 400.0, 600.0),
      const Rect.fromLTWH(800.0-80.0-400.0, 30.0, 400.0, 540.0),
      const Rect.fromLTWH(800.0-510.0-400.0, 0.0, 400.0, 600.0),
Ian Hickson's avatar
Ian Hickson committed
222 223
    ]);
    HitTestResult result;
224
    result = tester.hitTestOnBinding(const Offset(800.0-10.0, 10.0));
225
    expectIsTextSpan(result.path.first.target, 'before');
226
    result = tester.hitTestOnBinding(const Offset(800.0-60.0, 10.0));
Dan Field's avatar
Dan Field committed
227
    expect(result.path.first.target, isA<RenderView>());
228
    result = tester.hitTestOnBinding(const Offset(800.0-100.0, 100.0));
229
    expectIsTextSpan(result.path.first.target, 'padded');
230
    result = tester.hitTestOnBinding(const Offset(800.0-490.0, 100.0));
Dan Field's avatar
Dan Field committed
231
    expect(result.path.first.target, isA<RenderView>());
232
    result = tester.hitTestOnBinding(const Offset(800.0-520.0, 10.0));
233
    expectIsTextSpan(result.path.first.target, 'after');
Ian Hickson's avatar
Ian Hickson committed
234 235
  });

Adam Barth's avatar
Adam Barth committed
236
  testWidgets('Viewport+SliverPadding hit testing right', (WidgetTester tester) async {
237
    const EdgeInsets padding = EdgeInsets.all(30.0);
238
    await test(tester, 350.0, padding, AxisDirection.right, TextDirection.ltr);
Adam Barth's avatar
Adam Barth committed
239
    expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
Ian Hickson's avatar
Ian Hickson committed
240
    verify(tester, <Rect>[
Dan Field's avatar
Dan Field committed
241 242 243
      const Rect.fromLTWH(-350.0, 0.0, 400.0, 600.0),
      const Rect.fromLTWH(80.0, 30.0, 400.0, 540.0),
      const Rect.fromLTWH(510.0, 0.0, 400.0, 600.0),
Ian Hickson's avatar
Ian Hickson committed
244 245
    ]);
    HitTestResult result;
246
    result = tester.hitTestOnBinding(const Offset(10.0, 10.0));
247
    expectIsTextSpan(result.path.first.target, 'before');
248
    result = tester.hitTestOnBinding(const Offset(60.0, 10.0));
Dan Field's avatar
Dan Field committed
249
    expect(result.path.first.target, isA<RenderView>());
250
    result = tester.hitTestOnBinding(const Offset(100.0, 100.0));
251
    expectIsTextSpan(result.path.first.target, 'padded');
252
    result = tester.hitTestOnBinding(const Offset(490.0, 100.0));
Dan Field's avatar
Dan Field committed
253
    expect(result.path.first.target, isA<RenderView>());
254
    result = tester.hitTestOnBinding(const Offset(520.0, 10.0));
255
    expectIsTextSpan(result.path.first.target, 'after');
Ian Hickson's avatar
Ian Hickson committed
256 257
  });

Adam Barth's avatar
Adam Barth committed
258
  testWidgets('Viewport+SliverPadding no child', (WidgetTester tester) async {
259
    await tester.pumpWidget(
260
      Directionality(
261
        textDirection: TextDirection.ltr,
262 263
        child: Viewport(
          offset: ViewportOffset.fixed(0.0),
264
          slivers: const <Widget>[
265 266
            SliverPadding(padding: EdgeInsets.all(100.0)),
            SliverToBoxAdapter(child: SizedBox(width: 400.0, height: 400.0, child: Text('x'))),
267 268 269 270
          ],
        ),
      ),
    );
271
    expect(tester.renderObject<RenderBox>(find.text('x')).localToGlobal(Offset.zero), const Offset(0.0, 200.0));
Ian Hickson's avatar
Ian Hickson committed
272 273
  });

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
  testWidgets('SliverPadding with no child reports correct geometry as scroll offset changes', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/64506
    final ScrollController controller = ScrollController();
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: CustomScrollView(
          controller: controller,
          slivers: const <Widget>[
            SliverPadding(padding: EdgeInsets.all(100.0)),
            SliverToBoxAdapter(child: SizedBox(width: 400.0, height: 400.0, child: Text('x'))),
          ],
        ),
      ),
    );
    expect(tester.renderObject<RenderBox>(find.text('x')).localToGlobal(Offset.zero), const Offset(0.0, 200.0));
    expect(
      tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).geometry!.paintExtent,
      200.0,
    );
    controller.jumpTo(50.0);
    await tester.pump();
    expect(
      tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).geometry!.paintExtent,
      150.0,
    );
  });

Adam Barth's avatar
Adam Barth committed
302
  testWidgets('Viewport+SliverPadding changing padding', (WidgetTester tester) async {
303
    await tester.pumpWidget(
304
      Directionality(
305
        textDirection: TextDirection.ltr,
306
        child: Viewport(
307
          axisDirection: AxisDirection.left,
308
          offset: ViewportOffset.fixed(0.0),
309
          slivers: const <Widget>[
310 311
            SliverPadding(padding: EdgeInsets.fromLTRB(90.0, 1.0, 110.0, 2.0)),
            SliverToBoxAdapter(child: SizedBox(width: 201.0, child: Text('x'))),
312 313 314 315
          ],
        ),
      ),
    );
316
    expect(tester.renderObject<RenderBox>(find.text('x')).localToGlobal(Offset.zero), const Offset(399.0, 0.0));
317
    await tester.pumpWidget(
318
      Directionality(
319
        textDirection: TextDirection.ltr,
320
        child: Viewport(
321
          axisDirection: AxisDirection.left,
322
          offset: ViewportOffset.fixed(0.0),
323
          slivers: const <Widget>[
324 325
            SliverPadding(padding: EdgeInsets.fromLTRB(110.0, 1.0, 80.0, 2.0)),
            SliverToBoxAdapter(child: SizedBox(width: 201.0, child: Text('x'))),
326 327 328 329
          ],
        ),
      ),
    );
330
    expect(tester.renderObject<RenderBox>(find.text('x')).localToGlobal(Offset.zero), const Offset(409.0, 0.0));
Ian Hickson's avatar
Ian Hickson committed
331 332
  });

Adam Barth's avatar
Adam Barth committed
333
  testWidgets('Viewport+SliverPadding changing direction', (WidgetTester tester) async {
334
    await tester.pumpWidget(
335
      Directionality(
336
        textDirection: TextDirection.ltr,
337
        child: Viewport(
338
          axisDirection: AxisDirection.up,
339
          offset: ViewportOffset.fixed(0.0),
340
          slivers: const <Widget>[
341
            SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)),
342 343 344 345
          ],
        ),
      ),
    );
346
    expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 2.0);
347
    await tester.pumpWidget(
348
      Directionality(
349
        textDirection: TextDirection.ltr,
350 351
        child: Viewport(
          offset: ViewportOffset.fixed(0.0),
352
          slivers: const <Widget>[
353
            SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)),
354 355 356 357
          ],
        ),
      ),
    );
358
    expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 8.0);
359
    await tester.pumpWidget(
360
      Directionality(
361
        textDirection: TextDirection.ltr,
362
        child: Viewport(
363
          axisDirection: AxisDirection.right,
364
          offset: ViewportOffset.fixed(0.0),
365
          slivers: const <Widget>[
366
            SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)),
367 368 369 370
          ],
        ),
      ),
    );
371
    expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 4.0);
372
    await tester.pumpWidget(
373
      Directionality(
374
        textDirection: TextDirection.ltr,
375
        child: Viewport(
376
          axisDirection: AxisDirection.left,
377
          offset: ViewportOffset.fixed(0.0),
378
          slivers: const <Widget>[
379
            SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)),
380 381 382 383
          ],
        ),
      ),
    );
384
    expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 1.0);
385
    await tester.pumpWidget(
386
      Directionality(
387
        textDirection: TextDirection.ltr,
388
        child: Viewport(
389
          axisDirection: AxisDirection.left,
390
          offset: ViewportOffset.fixed(99999.9),
391
          slivers: const <Widget>[
392
            SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)),
393 394 395 396
          ],
        ),
      ),
    );
397
    expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding, skipOffstage: false)).afterPadding, 1.0);
Ian Hickson's avatar
Ian Hickson committed
398
  });
399 400 401

  testWidgets('SliverPadding propagates geometry offset corrections', (WidgetTester tester) async {
    Widget listBuilder(IndexedWidgetBuilder sliverChildBuilder) {
402
      return Directionality(
403
        textDirection: TextDirection.ltr,
404
        child: CustomScrollView(
405
          cacheExtent: 0.0,
406
          slivers: <Widget>[
407
            SliverPadding(
408
              padding: EdgeInsets.zero,
409 410
              sliver: SliverList(
                delegate: SliverChildBuilderDelegate(
411 412 413 414 415 416 417 418 419 420 421 422 423
                  sliverChildBuilder,
                  childCount: 10,
                ),
              ),
            ),
          ],
        ),
      );
    }

    await tester.pumpWidget(
      listBuilder(
        (BuildContext context, int index) {
424
          return SizedBox(
425
            height: 200.0,
426 427
            child: Center(
              child: Text(index.toString()),
428 429 430 431 432 433 434 435 436 437
            ),
          );
        },
      ),
    );

    await tester.drag(find.text('2'), const Offset(0.0, -300.0));
    await tester.pump();

    expect(
438
      tester.getRect(find.widgetWithText(SizedBox, '2')),
Dan Field's avatar
Dan Field committed
439
      const Rect.fromLTRB(0.0, 100.0, 800.0, 300.0),
440 441 442 443 444 445
    );

    // Now item 0 is 400.0px and going back will underflow.
    await tester.pumpWidget(
      listBuilder(
        (BuildContext context, int index) {
446
          return SizedBox(
447
            height: index == 0 ? 400.0 : 200.0,
448 449
            child: Center(
              child: Text(index.toString()),
450 451 452 453 454 455 456 457 458 459 460
            ),
          );
        },
      ),
    );

    await tester.drag(find.text('2'), const Offset(0.0, 300.0));
    // On this one frame, the scroll correction must properly propagate.
    await tester.pump();

    expect(
461
      tester.getRect(find.widgetWithText(SizedBox, '0')),
Dan Field's avatar
Dan Field committed
462
      const Rect.fromLTRB(0.0, -200.0, 800.0, 200.0),
463 464
    );
  });
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

  testWidgets('SliverPadding includes preceding padding in the precedingScrollExtent provided to child', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/49195
    final UniqueKey key = UniqueKey();
    await tester.pumpWidget(Directionality(
      textDirection: TextDirection.ltr,
      child: CustomScrollView(
        slivers: <Widget>[
          SliverPadding(
            padding: const EdgeInsets.only(top: 30),
            sliver: SliverFillRemaining(
              hasScrollBody: false,
              child: Container(
                key: key,
                color: Colors.red,
              ),
481
            ),
482
          ),
483
        ],
484 485 486 487 488 489 490 491 492 493 494 495 496 497
      ),
    ));
    await tester.pump();

    // The value of 570 is expected since SliverFillRemaining will fill all of
    // the space available to it. In this test, the extent of the viewport is
    // 600 pixels. If the SliverPadding widget provides the right constraints
    // to SliverFillRemaining, with 30 pixels preceding it, it should only have
    // a height of 570.
    expect(
      tester.renderObject<RenderBox>(find.byKey(key)).size.height,
      equals(570),
    );
  });
498

499
  testWidgets("SliverPadding consumes only its padding from the overlap of its parent's constraints", (WidgetTester tester) async {
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
    final _MockRenderSliver mock = _MockRenderSliver();
    final RenderSliverPadding renderObject = RenderSliverPadding(
      padding: const EdgeInsets.only(top: 20),
    );
    renderObject.child = mock;
    renderObject.layout(const SliverConstraints(
        viewportMainAxisExtent: 100.0,
        overlap: 100.0,
        cacheOrigin: 0.0,
        scrollOffset: 0.0,
        axisDirection: AxisDirection.down,
        growthDirection: GrowthDirection.forward,
        crossAxisExtent: 100.0,
        crossAxisDirection: AxisDirection.right,
        userScrollDirection: ScrollDirection.idle,
        remainingPaintExtent: 100.0,
        remainingCacheExtent: 100.0,
        precedingScrollExtent: 0.0,
      ),
      parentUsesSize: true,
    );
    expect(mock.constraints.overlap, 80.0);
  });

524
  testWidgets("SliverPadding passes the overlap to the child if it's negative", (WidgetTester tester) async {
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
    final _MockRenderSliver mock = _MockRenderSliver();
    final RenderSliverPadding renderObject = RenderSliverPadding(
      padding: const EdgeInsets.only(top: 20),
    );
    renderObject.child = mock;
    renderObject.layout(const SliverConstraints(
        viewportMainAxisExtent: 100.0,
        overlap: -100.0,
        cacheOrigin: 0.0,
        scrollOffset: 0.0,
        axisDirection: AxisDirection.down,
        growthDirection: GrowthDirection.forward,
        crossAxisExtent: 100.0,
        crossAxisDirection: AxisDirection.right,
        userScrollDirection: ScrollDirection.idle,
        remainingPaintExtent: 100.0,
        remainingCacheExtent: 100.0,
        precedingScrollExtent: 0.0,
      ),
      parentUsesSize: true,
    );
    expect(mock.constraints.overlap, -100.0);
  });

  testWidgets('SliverPadding passes the paintOrigin of the child on', (WidgetTester tester) async {
    final _MockRenderSliver mock = _MockRenderSliver();
    final RenderSliverPadding renderObject = RenderSliverPadding(
      padding: const EdgeInsets.only(top: 20),
    );
    renderObject.child = mock;
    renderObject.layout(const SliverConstraints(
        viewportMainAxisExtent: 100.0,
        overlap: 100.0,
        cacheOrigin: 0.0,
        scrollOffset: 0.0,
        axisDirection: AxisDirection.down,
        growthDirection: GrowthDirection.forward,
        crossAxisExtent: 100.0,
        crossAxisDirection: AxisDirection.right,
        userScrollDirection: ScrollDirection.idle,
        remainingPaintExtent: 100.0,
        remainingCacheExtent: 100.0,
        precedingScrollExtent: 0.0,
      ),
      parentUsesSize: true,
    );
571
    expect(renderObject.geometry!.paintOrigin, 10.0);
572
  });
Ian Hickson's avatar
Ian Hickson committed
573
}
574 575 576 577 578

void expectIsTextSpan(Object target, String text) {
  expect(target, isA<TextSpan>());
  expect((target as TextSpan).text, text);
}