1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
int globalGeneration = 0;
class GenerationText extends StatefulWidget {
const GenerationText(this.value, { Key? key }) : super(key: key);
final int value;
@override
State<GenerationText> createState() => _GenerationTextState();
}
class _GenerationTextState extends State<GenerationText> {
_GenerationTextState() : generation = globalGeneration;
final int generation;
@override
Widget build(BuildContext context) => Text('${widget.value}:$generation ', textDirection: TextDirection.ltr);
}
// Creates a SliverList with `keys.length` children and each child having a key from `keys` and a text of `key:generation`.
// The generation is increased with every call to this method.
Future<void> test(WidgetTester tester, double offset, List<int> keys) {
globalGeneration += 1;
return tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Viewport(
cacheExtent: 0.0,
offset: ViewportOffset.fixed(offset),
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate(keys.map<Widget>((int key) {
return SizedBox(key: GlobalObjectKey(key), height: 100.0, child: GenerationText(key));
}).toList()),
),
],
),
),
);
}
// `answerKey`: Expected offsets of visible SliverList children in global coordinate system.
// `text`: A space-separated list of expected `key:generation` pairs for the visible SliverList children.
void verify(WidgetTester tester, List<Offset> answerKey, String text) {
final List<Offset> testAnswers = tester.renderObjectList<RenderBox>(find.byType(SizedBox)).map<Offset>(
(RenderBox target) => target.localToGlobal(Offset.zero),
).toList();
expect(testAnswers, equals(answerKey));
final String foundText =
tester.widgetList<Text>(find.byType(Text))
.map<String>((Text widget) => widget.data!)
.reduce((String value, String element) => value + element);
expect(foundText, equals(text));
}
void main() {
testWidgets('Viewport+SliverBlock with GlobalKey reparenting', (WidgetTester tester) async {
await test(tester, 0.0, <int>[1,2,3,4,5,6,7,8,9]);
verify(tester, <Offset>[
Offset.zero,
const Offset(0.0, 100.0),
const Offset(0.0, 200.0),
const Offset(0.0, 300.0),
const Offset(0.0, 400.0),
const Offset(0.0, 500.0),
], '1:1 2:1 3:1 4:1 5:1 6:1 ');
// gen 2 - flipping the order:
await test(tester, 0.0, <int>[9,8,7,6,5,4,3,2,1]);
verify(tester, <Offset>[
Offset.zero,
const Offset(0.0, 100.0),
const Offset(0.0, 200.0),
const Offset(0.0, 300.0),
const Offset(0.0, 400.0),
const Offset(0.0, 500.0),
], '9:2 8:2 7:2 6:1 5:1 4:1 ');
// gen 3 - flipping the order back:
await test(tester, 0.0, <int>[1,2,3,4,5,6,7,8,9]);
verify(tester, <Offset>[
Offset.zero,
const Offset(0.0, 100.0),
const Offset(0.0, 200.0),
const Offset(0.0, 300.0),
const Offset(0.0, 400.0),
const Offset(0.0, 500.0),
], '1:3 2:3 3:3 4:1 5:1 6:1 ');
// gen 4 - removal:
await test(tester, 0.0, <int>[1,2,3,5,6,7,8,9]);
verify(tester, <Offset>[
Offset.zero,
const Offset(0.0, 100.0),
const Offset(0.0, 200.0),
const Offset(0.0, 300.0),
const Offset(0.0, 400.0),
const Offset(0.0, 500.0),
], '1:3 2:3 3:3 5:1 6:1 7:4 ');
// gen 5 - insertion:
await test(tester, 0.0, <int>[1,2,3,4,5,6,7,8,9]);
verify(tester, <Offset>[
Offset.zero,
const Offset(0.0, 100.0),
const Offset(0.0, 200.0),
const Offset(0.0, 300.0),
const Offset(0.0, 400.0),
const Offset(0.0, 500.0),
], '1:3 2:3 3:3 4:5 5:1 6:1 ');
// gen 6 - adjacent reordering:
await test(tester, 0.0, <int>[1,2,3,5,4,6,7,8,9]);
verify(tester, <Offset>[
Offset.zero,
const Offset(0.0, 100.0),
const Offset(0.0, 200.0),
const Offset(0.0, 300.0),
const Offset(0.0, 400.0),
const Offset(0.0, 500.0),
], '1:3 2:3 3:3 5:1 4:5 6:1 ');
// gen 7 - scrolling:
await test(tester, 120.0, <int>[1,2,3,5,4,6,7,8,9]);
verify(tester, <Offset>[
const Offset(0.0, -20.0),
const Offset(0.0, 80.0),
const Offset(0.0, 180.0),
const Offset(0.0, 280.0),
const Offset(0.0, 380.0),
const Offset(0.0, 480.0),
const Offset(0.0, 580.0),
], '2:3 3:3 5:1 4:5 6:1 7:7 8:7 ');
});
}