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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// 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/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
class TestSingleChildLayoutDelegate extends SingleChildLayoutDelegate {
late BoxConstraints constraintsFromGetSize;
BoxConstraints? constraintsFromGetConstraintsForChild;
late Size sizeFromGetPositionForChild;
late Size childSizeFromGetPositionForChild;
@override
Size getSize(BoxConstraints constraints) {
if (!RenderObject.debugCheckingIntrinsics) {
constraintsFromGetSize = constraints;
}
return const Size(200.0, 300.0);
}
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
assert(!RenderObject.debugCheckingIntrinsics);
constraintsFromGetConstraintsForChild = constraints;
return const BoxConstraints(minWidth: 100.0, maxWidth: 150.0, minHeight: 200.0, maxHeight: 400.0);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
assert(!RenderObject.debugCheckingIntrinsics);
sizeFromGetPositionForChild = size;
childSizeFromGetPositionForChild = childSize;
return Offset.zero;
}
bool shouldRelayoutCalled = false;
bool shouldRelayoutValue = false;
@override
bool shouldRelayout(_) {
assert(!RenderObject.debugCheckingIntrinsics);
shouldRelayoutCalled = true;
return shouldRelayoutValue;
}
}
class FixedSizeLayoutDelegate extends SingleChildLayoutDelegate {
FixedSizeLayoutDelegate(this.size);
final Size size;
@override
Size getSize(BoxConstraints constraints) => size;
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return BoxConstraints.tight(size);
}
@override
bool shouldRelayout(FixedSizeLayoutDelegate oldDelegate) {
return size != oldDelegate.size;
}
}
class NotifierLayoutDelegate extends SingleChildLayoutDelegate {
NotifierLayoutDelegate(this.size) : super(relayout: size);
final ValueNotifier<Size> size;
@override
Size getSize(BoxConstraints constraints) => size.value;
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return BoxConstraints.tight(size.value);
}
@override
bool shouldRelayout(NotifierLayoutDelegate oldDelegate) {
return size != oldDelegate.size;
}
}
Widget buildFrame(SingleChildLayoutDelegate delegate) {
return Center(
child: CustomSingleChildLayout(
delegate: delegate,
child: Container(),
),
);
}
void main() {
testWidgets('Control test for CustomSingleChildLayout', (WidgetTester tester) async {
final TestSingleChildLayoutDelegate delegate = TestSingleChildLayoutDelegate();
await tester.pumpWidget(buildFrame(delegate));
expect(delegate.constraintsFromGetSize.minWidth, 0.0);
expect(delegate.constraintsFromGetSize.maxWidth, 800.0);
expect(delegate.constraintsFromGetSize.minHeight, 0.0);
expect(delegate.constraintsFromGetSize.maxHeight, 600.0);
expect(delegate.constraintsFromGetConstraintsForChild!.minWidth, 0.0);
expect(delegate.constraintsFromGetConstraintsForChild!.maxWidth, 800.0);
expect(delegate.constraintsFromGetConstraintsForChild!.minHeight, 0.0);
expect(delegate.constraintsFromGetConstraintsForChild!.maxHeight, 600.0);
expect(delegate.sizeFromGetPositionForChild.width, 200.0);
expect(delegate.sizeFromGetPositionForChild.height, 300.0);
expect(delegate.childSizeFromGetPositionForChild.width, 150.0);
expect(delegate.childSizeFromGetPositionForChild.height, 400.0);
});
testWidgets('Test SingleChildDelegate shouldRelayout method', (WidgetTester tester) async {
TestSingleChildLayoutDelegate delegate =
TestSingleChildLayoutDelegate();
await tester.pumpWidget(buildFrame(delegate));
// Layout happened because the delegate was set.
expect(delegate.constraintsFromGetConstraintsForChild, isNotNull); // i.e. layout happened
expect(delegate.shouldRelayoutCalled, isFalse);
// Layout did not happen because shouldRelayout() returned false.
delegate = TestSingleChildLayoutDelegate();
delegate.shouldRelayoutValue = false;
await tester.pumpWidget(buildFrame(delegate));
expect(delegate.shouldRelayoutCalled, isTrue);
expect(delegate.constraintsFromGetConstraintsForChild, isNull);
// Layout happened because shouldRelayout() returned true.
delegate = TestSingleChildLayoutDelegate();
delegate.shouldRelayoutValue = true;
await tester.pumpWidget(buildFrame(delegate));
expect(delegate.shouldRelayoutCalled, isTrue);
expect(delegate.constraintsFromGetConstraintsForChild, isNotNull);
});
testWidgets('Delegate can change size', (WidgetTester tester) async {
await tester.pumpWidget(buildFrame(FixedSizeLayoutDelegate(const Size(100.0, 200.0))));
RenderBox box = tester.renderObject(find.byType(CustomSingleChildLayout));
expect(box.size, equals(const Size(100.0, 200.0)));
await tester.pumpWidget(buildFrame(FixedSizeLayoutDelegate(const Size(150.0, 240.0))));
box = tester.renderObject(find.byType(CustomSingleChildLayout));
expect(box.size, equals(const Size(150.0, 240.0)));
});
testWidgets('Can use listener for relayout', (WidgetTester tester) async {
final ValueNotifier<Size> size = ValueNotifier<Size>(const Size(100.0, 200.0));
await tester.pumpWidget(buildFrame(NotifierLayoutDelegate(size)));
RenderBox box = tester.renderObject(find.byType(CustomSingleChildLayout));
expect(box.size, equals(const Size(100.0, 200.0)));
size.value = const Size(150.0, 240.0);
await tester.pump();
box = tester.renderObject(find.byType(CustomSingleChildLayout));
expect(box.size, equals(const Size(150.0, 240.0)));
});
}