2
2
// Use of this source code is governed by a BSD-style license that can be
3
3
// found in the LICENSE file.
4
4
5
- import 'dart:math' as math;
6
5
import 'dart:ui' as ui;
7
6
8
7
import 'package:flutter/foundation.dart' ;
@@ -136,7 +135,7 @@ class AnimationSheetBuilder {
136
135
/// The frame is only recorded if the `recording` argument is true, or during
137
136
/// a procedure that is wrapped within [recording] . In either case, the
138
137
/// painted result of each frame will be stored and later available for
139
- /// [display ] . If neither condition is met, the frames are not recorded, which
138
+ /// [collate ] . If neither condition is met, the frames are not recorded, which
140
139
/// is useful during setup phases.
141
140
///
142
141
/// The `child` must not be null.
@@ -158,113 +157,6 @@ class AnimationSheetBuilder {
158
157
);
159
158
}
160
159
161
- /// Constructs a widget that renders the recorded frames in an animation sheet.
162
- ///
163
- /// The resulting widget takes as much space as its parent allows, which is
164
- /// usually the screen size. It is then filled with all recorded frames, each
165
- /// having a size specified by [frameSize] , chronologically from top-left to
166
- /// bottom-right in a row-major order.
167
- ///
168
- /// This widget does not check whether its size fits all recorded frames.
169
- /// Having too many frames can cause overflow errors, while having too few can
170
- /// waste the size of golden files. Therefore you should usually adjust the
171
- /// viewport size to [sheetSize] before calling this method.
172
- ///
173
- /// The `key` is applied to the root widget.
174
- ///
175
- /// This method can only be called if at least one frame has been recorded.
176
- ///
177
- /// The [display] is the legacy way of acquiring the output for comparison.
178
- /// It is not recommended because it requires more boilerplate, and produces
179
- /// a much large image than necessary: each pixel is rendered in 3x3 pixels
180
- /// without higher definition. Use [collate] instead.
181
- ///
182
- /// Using this way includes the following steps:
183
- ///
184
- /// * Create an instance of this class.
185
- /// * Pump frames that render the target widget wrapped in [record] . Every frame
186
- /// that has `recording` being true will be recorded.
187
- /// * Adjust the size of the test viewport to the [sheetSize] (see the
188
- /// documentation of [sheetSize] for more information).
189
- /// * Pump a frame that renders [display] , which shows all recorded frames in an
190
- /// animation sheet, and can be matched against the golden test.
191
- ///
192
- /// {@tool snippet}
193
- /// The following example shows how to record an animation sheet of an [InkWell]
194
- /// being pressed then released.
195
- ///
196
- /// ```dart
197
- /// testWidgets('Inkwell animation sheet', (WidgetTester tester) async {
198
- /// // Create instance
199
- /// final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(48, 24));
200
- ///
201
- /// final Widget target = Material(
202
- /// child: Directionality(
203
- /// textDirection: TextDirection.ltr,
204
- /// child: InkWell(
205
- /// splashColor: Colors.blue,
206
- /// onTap: () {},
207
- /// ),
208
- /// ),
209
- /// );
210
- ///
211
- /// // Optional: setup before recording (`recording` is false)
212
- /// await tester.pumpWidget(animationSheet.record(
213
- /// target,
214
- /// recording: false,
215
- /// ));
216
- ///
217
- /// final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(InkWell)));
218
- ///
219
- /// // Start recording (`recording` is true)
220
- /// await tester.pumpFrames(animationSheet.record(
221
- /// target,
222
- /// recording: true,
223
- /// ), const Duration(seconds: 1));
224
- ///
225
- /// await gesture.up();
226
- ///
227
- /// await tester.pumpFrames(animationSheet.record(
228
- /// target,
229
- /// recording: true,
230
- /// ), const Duration(seconds: 1));
231
- ///
232
- /// // Adjust view port size
233
- /// tester.binding.setSurfaceSize(animationSheet.sheetSize());
234
- ///
235
- /// // Display
236
- /// final Widget display = await animationSheet.display();
237
- /// await tester.pumpWidget(display);
238
- ///
239
- /// // Compare against golden file
240
- /// await expectLater(
241
- /// find.byWidget(display),
242
- /// matchesGoldenFile('inkwell.press.animation.png'),
243
- /// );
244
- /// }, skip: isBrowser); // Animation sheet does not support browser https://github.com/flutter/flutter/issues/56001
245
- /// ```
246
- /// {@end-tool}
247
- @Deprecated (
248
- 'Use AnimationSheetBuilder.collate instead. '
249
- 'This feature was deprecated after v2.3.0-13.0.pre.' ,
250
- )
251
- Future <Widget > display ({Key ? key}) async {
252
- assert (_recordedFrames.isNotEmpty);
253
- final List <ui.Image > frames = await _frames;
254
- return _CellSheet (
255
- key: key,
256
- cellSize: frameSize,
257
- children: frames.map ((ui.Image image) => RawImage (
258
- image: image.clone (),
259
- width: frameSize.width,
260
- height: frameSize.height,
261
- // Disable quality enhancement because the point of this class is to
262
- // precisely record what the widget looks like.
263
- filterQuality: ui.FilterQuality .none,
264
- )).toList (),
265
- );
266
- }
267
-
268
160
/// Returns an result image by putting all frames together in a table.
269
161
///
270
162
/// This method returns a table of captured frames, `cellsPerRow` images
@@ -277,39 +169,6 @@ class AnimationSheetBuilder {
277
169
'No frames are collected. Have you forgot to set `recording` to true?' );
278
170
return _collateFrames (frames, frameSize, cellsPerRow);
279
171
}
280
-
281
- /// Returns the smallest size that can contain all recorded frames.
282
- ///
283
- /// This is used to adjust the viewport during unit tests, i.e. the size of
284
- /// virtual screen. Having too many frames recorded than the default viewport
285
- /// size can contain will lead to overflow errors, while having too few frames
286
- /// means the golden file might be larger than necessary.
287
- ///
288
- /// The [sheetSize] returns the smallest possible size by placing the
289
- /// recorded frames, each of which has a size specified by [frameSize] , in a
290
- /// row-major grid with a maximum width specified by `maxWidth` , and returns
291
- /// the size of that grid.
292
- ///
293
- /// Setting the viewport size during a widget test usually involves
294
- /// [TestWidgetsFlutterBinding.setSurfaceSize] and [WidgetTester.binding] .
295
- ///
296
- /// The `maxWidth` defaults to the width of the default viewport, 800.0.
297
- ///
298
- /// This method can only be called if at least one frame has been recorded.
299
- @Deprecated (
300
- 'The `sheetSize` is only useful for `display`, which should be migrated to `collate`. '
301
- 'This feature was deprecated after v2.3.0-13.0.pre.' ,
302
- )
303
- Size sheetSize ({double maxWidth = _kDefaultTestViewportWidth}) {
304
- assert (_recordedFrames.isNotEmpty);
305
- final int cellsPerRow = (maxWidth / frameSize.width).floor ();
306
- final int rowNum = (_recordedFrames.length / cellsPerRow).ceil ();
307
- final double width = math.min (cellsPerRow, _recordedFrames.length) * frameSize.width;
308
- return Size (width, frameSize.height * rowNum);
309
- }
310
-
311
- // The width of _kDefaultTestViewportSize in [TestViewConfiguration].
312
- static const double _kDefaultTestViewportWidth = 800.0 ;
313
172
}
314
173
315
174
typedef _RecordedHandler = void Function (Future <ui.Image > image);
@@ -446,45 +305,6 @@ Future<ui.Image> _collateFrames(List<ui.Image> frames, Size frameSize, int cells
446
305
return image;
447
306
}
448
307
449
- // Layout children in a grid of fixed-sized cells.
450
- //
451
- // The sheet fills up as much space as the parent allows. The cells are
452
- // positioned from top left to bottom right in a row-major order.
453
- class _CellSheet extends StatelessWidget {
454
- _CellSheet ({
455
- super .key,
456
- required this .cellSize,
457
- required this .children,
458
- }) : assert (children.isNotEmpty);
459
-
460
- final Size cellSize;
461
- final List <Widget > children;
462
-
463
- @override
464
- Widget build (BuildContext context) {
465
- return LayoutBuilder (builder: (BuildContext context, BoxConstraints constraints) {
466
- final double rowWidth = constraints.biggest.width;
467
- final int cellsPerRow = (rowWidth / cellSize.width).floor ();
468
- final List <Widget > rows = < Widget > [];
469
- for (int rowStart = 0 ; rowStart < children.length; rowStart += cellsPerRow) {
470
- final Iterable <Widget > rowTargets = children.sublist (rowStart, math.min (rowStart + cellsPerRow, children.length));
471
- rows.add (Row (
472
- textDirection: TextDirection .ltr,
473
- children: rowTargets.map ((Widget target) => SizedBox .fromSize (
474
- size: cellSize,
475
- child: target,
476
- )).toList (),
477
- ));
478
- }
479
- return Column (
480
- textDirection: TextDirection .ltr,
481
- crossAxisAlignment: CrossAxisAlignment .start,
482
- children: rows,
483
- );
484
- });
485
- }
486
- }
487
-
488
308
class _RenderRootableRepaintBoundary extends RenderRepaintBoundary {
489
309
// Like [toImage], but captures an image of all layers (composited by
490
310
// RenderView and its children) clipped by the region of this object.
0 commit comments