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

import 'dart:io' show Platform;

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

class Leaf extends StatefulWidget {
12
  const Leaf({
13
    super.key,
14
    required this.child,
15
  });
16 17
  final Widget child;
  @override
18
  State<Leaf> createState() => _LeafState();
19 20 21 22 23 24 25 26 27 28 29
}

class _LeafState extends State<Leaf> {
  bool _keepAlive = false;

  void setKeepAlive(bool value) {
    setState(() { _keepAlive = value; });
  }

  @override
  Widget build(BuildContext context) {
30
    return KeepAlive(
31 32 33 34 35 36 37
      keepAlive: _keepAlive,
      child: widget.child,
    );
  }
}

List<Widget> generateList(Widget child) {
38
  return List<Widget>.generate(
39
    100,
40 41
    (int index) => Leaf(
      key: GlobalObjectKey<_LeafState>(index),
42 43 44 45 46 47 48 49
      child: child,
    ),
    growable: false,
  );
}

void main() {
  testWidgets('KeepAlive with ListView with itemExtent', (WidgetTester tester) async {
50
    await tester.pumpWidget(
51
      Directionality(
52
        textDirection: TextDirection.ltr,
53
        child: ListView(
54
          cacheExtent: 0.0,
55 56
          addAutomaticKeepAlives: false,
          addRepaintBoundaries: false,
57
          addSemanticIndexes: false,
58 59 60 61 62
          itemExtent: 12.3, // about 50 widgets visible
          children: generateList(const Placeholder()),
        ),
      ),
    );
63 64
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
65 66 67 68
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
69 70
    await tester.drag(find.byType(ListView), const Offset(0.0, -300.0)); // about 25 widgets' worth
    await tester.pump();
71
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3), skipOffstage: false), findsNothing);
72 73 74 75
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61)), findsOneWidget);
76
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
77
    const GlobalObjectKey<_LeafState>(60).currentState!.setKeepAlive(true);
78 79 80 81
    await tester.drag(find.byType(ListView), const Offset(0.0, 300.0)); // back to top
    await tester.pump();
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
82 83 84 85 86
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60)), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
87
    const GlobalObjectKey<_LeafState>(60).currentState!.setKeepAlive(false);
88 89 90
    await tester.pump();
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
91 92 93 94
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
95 96 97
  });

  testWidgets('KeepAlive with ListView without itemExtent', (WidgetTester tester) async {
98
    await tester.pumpWidget(
99
      Directionality(
100
        textDirection: TextDirection.ltr,
101
        child: ListView(
102
          cacheExtent: 0.0,
103 104
          addAutomaticKeepAlives: false,
          addRepaintBoundaries: false,
105
          addSemanticIndexes: false,
106
          children: generateList(const SizedBox(height: 12.3, child: Placeholder())), // about 50 widgets visible
107 108 109
        ),
      ),
    );
110 111
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
112 113 114 115
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
116 117
    await tester.drag(find.byType(ListView), const Offset(0.0, -300.0)); // about 25 widgets' worth
    await tester.pump();
118
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3), skipOffstage: false), findsNothing);
119 120 121 122
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61)), findsOneWidget);
123
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
124
    const GlobalObjectKey<_LeafState>(60).currentState!.setKeepAlive(true);
125 126 127 128
    await tester.drag(find.byType(ListView), const Offset(0.0, 300.0)); // back to top
    await tester.pump();
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
129 130 131 132 133
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60)), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
134
    const GlobalObjectKey<_LeafState>(60).currentState!.setKeepAlive(false);
135 136 137
    await tester.pump();
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
138 139 140 141
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
142 143 144
  });

  testWidgets('KeepAlive with GridView', (WidgetTester tester) async {
145
    await tester.pumpWidget(
146
      Directionality(
147
        textDirection: TextDirection.ltr,
148
        child: GridView.count(
149
          cacheExtent: 0.0,
150 151
          addAutomaticKeepAlives: false,
          addRepaintBoundaries: false,
152
          addSemanticIndexes: false,
153 154
          crossAxisCount: 2,
          childAspectRatio: 400.0 / 24.6, // about 50 widgets visible
155
          children: generateList(const Placeholder()),
156 157 158
        ),
      ),
    );
159 160
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
161 162 163 164
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
165 166
    await tester.drag(find.byType(GridView), const Offset(0.0, -300.0)); // about 25 widgets' worth
    await tester.pump();
167
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3), skipOffstage: false), findsNothing);
168 169 170 171
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61)), findsOneWidget);
172
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
173
    const GlobalObjectKey<_LeafState>(60).currentState!.setKeepAlive(true);
174 175 176 177
    await tester.drag(find.byType(GridView), const Offset(0.0, 300.0)); // back to top
    await tester.pump();
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
178 179 180 181 182
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60)), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
183
    const GlobalObjectKey<_LeafState>(60).currentState!.setKeepAlive(false);
184 185 186
    await tester.pump();
    expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(30)), findsOneWidget);
187 188 189 190
    expect(find.byKey(const GlobalObjectKey<_LeafState>(59), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(60), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(61), skipOffstage: false), findsNothing);
    expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing);
191 192 193
  });

  testWidgets('KeepAlive render tree description', (WidgetTester tester) async {
194
    await tester.pumpWidget(
195
      Directionality(
196
        textDirection: TextDirection.ltr,
197
        child: ListView(
198 199
          addAutomaticKeepAlives: false,
          addRepaintBoundaries: false,
200
          addSemanticIndexes: false,
201 202 203 204 205
          itemExtent: 400.0, // 2 visible children
          children: generateList(const Placeholder()),
        ),
      ),
    );
206
    // The important lines below are the ones marked with "<----"
207
    expect(tester.binding.renderView.toStringDeep(minLevel: DiagnosticLevel.info), equalsIgnoringHashCodes(
208 209 210 211 212 213 214
      'RenderView#00000\n'
      ' │ debug mode enabled - ${Platform.operatingSystem}\n'
      ' │ window size: Size(2400.0, 1800.0) (in physical pixels)\n'
      ' │ device pixel ratio: 3.0 (physical pixels per logical pixel)\n'
      ' │ configuration: Size(800.0, 600.0) at 3.0x (in logical pixels)\n'
      ' │\n'
      ' └─child: RenderRepaintBoundary#00000\n'
215
      '   │ needs compositing\n'
216 217 218 219 220 221 222 223 224
      '   │ parentData: <none>\n'
      '   │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '   │ layer: OffsetLayer#00000\n'
      '   │ size: Size(800.0, 600.0)\n'
      '   │ metrics: 0.0% useful (1 bad vs 0 good)\n'
      '   │ diagnosis: insufficient data to draw conclusion (less than five\n'
      '   │   repaints)\n'
      '   │\n'
      '   └─child: RenderCustomPaint#00000\n'
225
      '     │ needs compositing\n'
226 227 228
      '     │ parentData: <none> (can use size)\n'
      '     │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '     │ size: Size(800.0, 600.0)\n'
Ian Hickson's avatar
Ian Hickson committed
229 230 231 232 233
      '     │ painter: null\n'
      '     │ foregroundPainter:\n'
      '     │   _GlowingOverscrollIndicatorPainter(_GlowController(color:\n'
      '     │   Color(0xffffffff), axis: vertical), _GlowController(color:\n'
      '     │   Color(0xffffffff), axis: vertical))\n'
234 235
      '     │\n'
      '     └─child: RenderRepaintBoundary#00000\n'
236
      '       │ needs compositing\n'
237 238 239 240 241 242 243 244
      '       │ parentData: <none> (can use size)\n'
      '       │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '       │ layer: OffsetLayer#00000\n'
      '       │ size: Size(800.0, 600.0)\n'
      '       │ metrics: 0.0% useful (1 bad vs 0 good)\n'
      '       │ diagnosis: insufficient data to draw conclusion (less than five\n'
      '       │   repaints)\n'
      '       │\n'
Ian Hickson's avatar
Ian Hickson committed
245
      '       └─child: _RenderScrollSemantics#00000\n'
246
      '         │ needs compositing\n'
247 248
      '         │ parentData: <none> (can use size)\n'
      '         │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
249
      '         │ semantics node: SemanticsNode#1\n'
250
      '         │ semantic boundary\n'
251 252
      '         │ size: Size(800.0, 600.0)\n'
      '         │\n'
253
      '         └─child: RenderPointerListener#00000\n'
254
      '           │ needs compositing\n'
255 256 257
      '           │ parentData: <none> (can use size)\n'
      '           │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '           │ size: Size(800.0, 600.0)\n'
258 259
      '           │ behavior: deferToChild\n'
      '           │ listeners: signal\n'
260
      '           │\n'
261
      '           └─child: RenderSemanticsGestureHandler#00000\n'
262
      '             │ needs compositing\n'
263 264 265
      '             │ parentData: <none> (can use size)\n'
      '             │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '             │ size: Size(800.0, 600.0)\n'
266
      '             │ behavior: opaque\n'
267
      '             │ gestures: vertical scroll\n'
268
      '             │\n'
269
      '             └─child: RenderPointerListener#00000\n'
270
      '               │ needs compositing\n'
271 272 273
      '               │ parentData: <none> (can use size)\n'
      '               │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '               │ size: Size(800.0, 600.0)\n'
274
      '               │ behavior: opaque\n'
275
      '               │ listeners: down, panZoomStart\n'
276
      '               │\n'
277
      '               └─child: RenderSemanticsAnnotations#00000\n'
278
      '                 │ needs compositing\n'
279 280 281
      '                 │ parentData: <none> (can use size)\n'
      '                 │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '                 │ size: Size(800.0, 600.0)\n'
282
      '                 │\n'
283
      '                 └─child: RenderIgnorePointer#00000\n'
284
      '                   │ needs compositing\n'
285 286 287
      '                   │ parentData: <none> (can use size)\n'
      '                   │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '                   │ size: Size(800.0, 600.0)\n'
288 289
      '                   │ ignoring: false\n'
      '                   │ ignoringSemantics: false\n'
290
      '                   │\n'
291
      '                   └─child: RenderViewport#00000\n'
292
      '                     │ needs compositing\n'
293 294 295 296 297 298 299 300
      '                     │ parentData: <none> (can use size)\n'
      '                     │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '                     │ layer: OffsetLayer#00000\n'
      '                     │ size: Size(800.0, 600.0)\n'
      '                     │ axisDirection: down\n'
      '                     │ crossAxisDirection: right\n'
      '                     │ offset: ScrollPositionWithSingleContext#00000(offset: 0.0, range:\n'
      '                     │   0.0..39400.0, viewport: 600.0, ScrollableState,\n'
301 302 303
      '                     │   AlwaysScrollableScrollPhysics -> ClampingScrollPhysics ->\n'
      '                     │   RangeMaintainingScrollPhysics, IdleScrollActivity#00000,\n'
      '                     │   ScrollDirection.idle)\n'
304
      '                     │ anchor: 0.0\n'
305
      '                     │\n'
306 307 308 309 310 311
      '                     └─center child: RenderSliverFixedExtentList#00000 relayoutBoundary=up1\n'
      '                       │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
      '                       │ constraints: SliverConstraints(AxisDirection.down,\n'
      '                       │   GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
      '                       │   0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
      '                       │   crossAxisDirection: AxisDirection.right,\n'
312 313
      '                       │   viewportMainAxisExtent: 600.0, remainingCacheExtent: 850.0,\n'
      '                       │   cacheOrigin: 0.0)\n'
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
      '                       │ geometry: SliverGeometry(scrollExtent: 40000.0, paintExtent:\n'
      '                       │   600.0, maxPaintExtent: 40000.0, hasVisualOverflow: true,\n'
      '                       │   cacheExtent: 850.0)\n'
      '                       │ currently live children: 0 to 2\n'
      '                       │\n'
      '                       ├─child with index 0: RenderLimitedBox#00000\n'
      '                       │ │ parentData: index=0; layoutOffset=0.0\n'
      '                       │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │ │ size: Size(800.0, 400.0)\n'
      '                       │ │ maxWidth: 400.0\n'
      '                       │ │ maxHeight: 400.0\n'
      '                       │ │\n'
      '                       │ └─child: RenderCustomPaint#00000\n'
      '                       │     parentData: <none> (can use size)\n'
      '                       │     constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │     size: Size(800.0, 400.0)\n'
330
      '                       │     painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
331
      '                       │     preferredSize: Size(Infinity, Infinity)\n'
332
      '                       │\n'
333 334 335 336 337 338 339 340 341 342 343
      '                       ├─child with index 1: RenderLimitedBox#00000\n'                                     // <----- no dashed line starts here
      '                       │ │ parentData: index=1; layoutOffset=400.0\n'
      '                       │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │ │ size: Size(800.0, 400.0)\n'
      '                       │ │ maxWidth: 400.0\n'
      '                       │ │ maxHeight: 400.0\n'
      '                       │ │\n'
      '                       │ └─child: RenderCustomPaint#00000\n'
      '                       │     parentData: <none> (can use size)\n'
      '                       │     constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │     size: Size(800.0, 400.0)\n'
344
      '                       │     painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
345
      '                       │     preferredSize: Size(Infinity, Infinity)\n'
346 347 348 349 350 351 352 353 354 355 356
      '                       │\n'
      '                       └─child with index 2: RenderLimitedBox#00000 NEEDS-PAINT\n'
      '                         │ parentData: index=2; layoutOffset=800.0\n'
      '                         │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                         │ size: Size(800.0, 400.0)\n'
      '                         │ maxWidth: 400.0\n'
      '                         │ maxHeight: 400.0\n'
      '                         │\n'
      '                         └─child: RenderCustomPaint#00000 NEEDS-PAINT\n'
      '                             parentData: <none> (can use size)\n'
      '                             constraints: BoxConstraints(w=800.0, h=400.0)\n'
Ian Hickson's avatar
Ian Hickson committed
357
      '                             size: Size(800.0, 400.0)\n'
358
      '                             painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
359
      '                             preferredSize: Size(Infinity, Infinity)\n',
360
    ));
361
    const GlobalObjectKey<_LeafState>(0).currentState!.setKeepAlive(true);
362 363
    await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0));
    await tester.pump();
364
    const GlobalObjectKey<_LeafState>(3).currentState!.setKeepAlive(true);
365 366
    await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0));
    await tester.pump();
367
    expect(tester.binding.renderView.toStringDeep(minLevel: DiagnosticLevel.info), equalsIgnoringHashCodes(
368 369 370 371 372 373 374
      'RenderView#00000\n'
      ' │ debug mode enabled - ${Platform.operatingSystem}\n'
      ' │ window size: Size(2400.0, 1800.0) (in physical pixels)\n'
      ' │ device pixel ratio: 3.0 (physical pixels per logical pixel)\n'
      ' │ configuration: Size(800.0, 600.0) at 3.0x (in logical pixels)\n'
      ' │\n'
      ' └─child: RenderRepaintBoundary#00000\n'
375
      '   │ needs compositing\n'
376 377 378 379 380 381 382 383 384
      '   │ parentData: <none>\n'
      '   │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '   │ layer: OffsetLayer#00000\n'
      '   │ size: Size(800.0, 600.0)\n'
      '   │ metrics: 0.0% useful (1 bad vs 0 good)\n'
      '   │ diagnosis: insufficient data to draw conclusion (less than five\n'
      '   │   repaints)\n'
      '   │\n'
      '   └─child: RenderCustomPaint#00000\n'
385
      '     │ needs compositing\n'
386 387 388
      '     │ parentData: <none> (can use size)\n'
      '     │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '     │ size: Size(800.0, 600.0)\n'
Ian Hickson's avatar
Ian Hickson committed
389 390 391 392 393
      '     │ painter: null\n'
      '     │ foregroundPainter:\n'
      '     │   _GlowingOverscrollIndicatorPainter(_GlowController(color:\n'
      '     │   Color(0xffffffff), axis: vertical), _GlowController(color:\n'
      '     │   Color(0xffffffff), axis: vertical))\n'
394 395
      '     │\n'
      '     └─child: RenderRepaintBoundary#00000\n'
396
      '       │ needs compositing\n'
397 398 399 400 401 402 403 404
      '       │ parentData: <none> (can use size)\n'
      '       │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '       │ layer: OffsetLayer#00000\n'
      '       │ size: Size(800.0, 600.0)\n'
      '       │ metrics: 0.0% useful (1 bad vs 0 good)\n'
      '       │ diagnosis: insufficient data to draw conclusion (less than five\n'
      '       │   repaints)\n'
      '       │\n'
Ian Hickson's avatar
Ian Hickson committed
405
      '       └─child: _RenderScrollSemantics#00000\n'
406
      '         │ needs compositing\n'
407 408
      '         │ parentData: <none> (can use size)\n'
      '         │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
409
      '         │ semantics node: SemanticsNode#1\n'
410
      '         │ semantic boundary\n'
411 412
      '         │ size: Size(800.0, 600.0)\n'
      '         │\n'
413
      '         └─child: RenderPointerListener#00000\n'
414
      '           │ needs compositing\n'
415 416 417
      '           │ parentData: <none> (can use size)\n'
      '           │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '           │ size: Size(800.0, 600.0)\n'
418 419
      '           │ behavior: deferToChild\n'
      '           │ listeners: signal\n'
420
      '           │\n'
421
      '           └─child: RenderSemanticsGestureHandler#00000\n'
422
      '             │ needs compositing\n'
423 424 425
      '             │ parentData: <none> (can use size)\n'
      '             │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '             │ size: Size(800.0, 600.0)\n'
426
      '             │ behavior: opaque\n'
427
      '             │ gestures: vertical scroll\n'
428
      '             │\n'
429
      '             └─child: RenderPointerListener#00000\n'
430
      '               │ needs compositing\n'
431 432 433
      '               │ parentData: <none> (can use size)\n'
      '               │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '               │ size: Size(800.0, 600.0)\n'
434
      '               │ behavior: opaque\n'
435
      '               │ listeners: down, panZoomStart\n'
436
      '               │\n'
437
      '               └─child: RenderSemanticsAnnotations#00000\n'
438
      '                 │ needs compositing\n'
439 440 441
      '                 │ parentData: <none> (can use size)\n'
      '                 │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '                 │ size: Size(800.0, 600.0)\n'
442
      '                 │\n'
443
      '                 └─child: RenderIgnorePointer#00000\n'
444
      '                   │ needs compositing\n'
445 446 447
      '                   │ parentData: <none> (can use size)\n'
      '                   │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '                   │ size: Size(800.0, 600.0)\n'
448 449
      '                   │ ignoring: false\n'
      '                   │ ignoringSemantics: false\n'
450
      '                   │\n'
451
      '                   └─child: RenderViewport#00000\n'
452
      '                     │ needs compositing\n'
453 454 455 456 457 458 459 460
      '                     │ parentData: <none> (can use size)\n'
      '                     │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
      '                     │ layer: OffsetLayer#00000\n'
      '                     │ size: Size(800.0, 600.0)\n'
      '                     │ axisDirection: down\n'
      '                     │ crossAxisDirection: right\n'
      '                     │ offset: ScrollPositionWithSingleContext#00000(offset: 2000.0,\n'
      '                     │   range: 0.0..39400.0, viewport: 600.0, ScrollableState,\n'
461 462 463
      '                     │   AlwaysScrollableScrollPhysics -> ClampingScrollPhysics ->\n'
      '                     │   RangeMaintainingScrollPhysics, IdleScrollActivity#00000,\n'
      '                     │   ScrollDirection.idle)\n'
464
      '                     │ anchor: 0.0\n'
465
      '                     │\n'
466 467 468 469 470 471
      '                     └─center child: RenderSliverFixedExtentList#00000 relayoutBoundary=up1\n'
      '                       │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
      '                       │ constraints: SliverConstraints(AxisDirection.down,\n'
      '                       │   GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
      '                       │   2000.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
      '                       │   crossAxisDirection: AxisDirection.right,\n'
472 473
      '                       │   viewportMainAxisExtent: 600.0, remainingCacheExtent: 1100.0,\n'
      '                       │   cacheOrigin: -250.0)\n'
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
      '                       │ geometry: SliverGeometry(scrollExtent: 40000.0, paintExtent:\n'
      '                       │   600.0, maxPaintExtent: 40000.0, hasVisualOverflow: true,\n'
      '                       │   cacheExtent: 1100.0)\n'
      '                       │ currently live children: 4 to 7\n'
      '                       │\n'
      '                       ├─child with index 4: RenderLimitedBox#00000 NEEDS-PAINT\n'
      '                       │ │ parentData: index=4; layoutOffset=1600.0\n'
      '                       │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │ │ size: Size(800.0, 400.0)\n'
      '                       │ │ maxWidth: 400.0\n'
      '                       │ │ maxHeight: 400.0\n'
      '                       │ │\n'
      '                       │ └─child: RenderCustomPaint#00000 NEEDS-PAINT\n'
      '                       │     parentData: <none> (can use size)\n'
      '                       │     constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │     size: Size(800.0, 400.0)\n'
490
      '                       │     painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
491
      '                       │     preferredSize: Size(Infinity, Infinity)\n'
492 493 494 495 496 497 498 499 500 501 502 503
      '                       │\n'
      '                       ├─child with index 5: RenderLimitedBox#00000\n'                                     // <----- this is index 5, not 0
      '                       │ │ parentData: index=5; layoutOffset=2000.0\n'
      '                       │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │ │ size: Size(800.0, 400.0)\n'
      '                       │ │ maxWidth: 400.0\n'
      '                       │ │ maxHeight: 400.0\n'
      '                       │ │\n'
      '                       │ └─child: RenderCustomPaint#00000\n'
      '                       │     parentData: <none> (can use size)\n'
      '                       │     constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │     size: Size(800.0, 400.0)\n'
504
      '                       │     painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
505
      '                       │     preferredSize: Size(Infinity, Infinity)\n'
506 507 508 509 510 511 512 513 514 515 516 517
      '                       │\n'
      '                       ├─child with index 6: RenderLimitedBox#00000\n'
      '                       │ │ parentData: index=6; layoutOffset=2400.0\n'
      '                       │ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │ │ size: Size(800.0, 400.0)\n'
      '                       │ │ maxWidth: 400.0\n'
      '                       │ │ maxHeight: 400.0\n'
      '                       │ │\n'
      '                       │ └─child: RenderCustomPaint#00000\n'
      '                       │     parentData: <none> (can use size)\n'
      '                       │     constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       │     size: Size(800.0, 400.0)\n'
518
      '                       │     painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
519
      '                       │     preferredSize: Size(Infinity, Infinity)\n'
520
      '                       │\n'
521 522 523 524 525 526 527 528 529 530 531
      '                       ├─child with index 7: RenderLimitedBox#00000 NEEDS-PAINT\n'
      '                       ╎ │ parentData: index=7; layoutOffset=2800.0\n'
      '                       ╎ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       ╎ │ size: Size(800.0, 400.0)\n'
      '                       ╎ │ maxWidth: 400.0\n'
      '                       ╎ │ maxHeight: 400.0\n'
      '                       ╎ │\n'
      '                       ╎ └─child: RenderCustomPaint#00000 NEEDS-PAINT\n'
      '                       ╎     parentData: <none> (can use size)\n'
      '                       ╎     constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       ╎     size: Size(800.0, 400.0)\n'
532
      '                       ╎     painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
533
      '                       ╎     preferredSize: Size(Infinity, Infinity)\n'
534 535 536 537 538 539 540 541 542 543 544 545
      '                       ╎\n'
      '                       ╎╌child with index 0 (kept alive but not laid out): RenderLimitedBox#00000\n'               // <----- this one is index 0 and is marked as being kept alive but not laid out
      '                       ╎ │ parentData: index=0; keepAlive; layoutOffset=0.0\n'
      '                       ╎ │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       ╎ │ size: Size(800.0, 400.0)\n'
      '                       ╎ │ maxWidth: 400.0\n'
      '                       ╎ │ maxHeight: 400.0\n'
      '                       ╎ │\n'
      '                       ╎ └─child: RenderCustomPaint#00000\n'
      '                       ╎     parentData: <none> (can use size)\n'
      '                       ╎     constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                       ╎     size: Size(800.0, 400.0)\n'
546
      '                       ╎     painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
547
      '                       ╎     preferredSize: Size(Infinity, Infinity)\n'
548 549 550 551 552 553 554 555 556 557 558
      '                       ╎\n'                                                                                // <----- dashed line ends here
      '                       └╌child with index 3 (kept alive but not laid out): RenderLimitedBox#00000\n'
      '                         │ parentData: index=3; keepAlive; layoutOffset=1200.0\n'
      '                         │ constraints: BoxConstraints(w=800.0, h=400.0)\n'
      '                         │ size: Size(800.0, 400.0)\n'
      '                         │ maxWidth: 400.0\n'
      '                         │ maxHeight: 400.0\n'
      '                         │\n'
      '                         └─child: RenderCustomPaint#00000\n'
      '                             parentData: <none> (can use size)\n'
      '                             constraints: BoxConstraints(w=800.0, h=400.0)\n'
Ian Hickson's avatar
Ian Hickson committed
559
      '                             size: Size(800.0, 400.0)\n'
560
      '                             painter: _PlaceholderPainter#00000()\n'
Ian Hickson's avatar
Ian Hickson committed
561
      '                             preferredSize: Size(Infinity, Infinity)\n',
562
    ));
563
  }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/87876
564 565

}