The `AnimationSheetBuilder.display` and `sheetSize` methods are deprecated, and should be replaced with `AnimationSheetBuilder.collate`.
Original behavior
`AnimationSheetBuilder` is a testing utility class that records frames of an animating widget, and later composes the frames into a single animation sheet for golden testing. The old way of composing involves `display` to list the images into a table-like widget, adjusting the testing surface with `sheetSize`, and capturing the table widget for comparison. A new way, `collate`, has been added that directly puts the frames together into an image for comparison, which requires less boilerplate code and outputs a smaller image without compromise in quality. APIs for the old way are thus deprecate
New behavior
The following changes have been made to the `AnimationSheetBuilder` class:
- Who is affected
- Applications and packages relying on the previous behaviour or signature. Code that uses AnimationSheetBuilder.display, AnimationSheetBuilder.collate, AnimationSheetBuilder.
- Practical impact
- Behaviour or API differences that can break builds or change runtime behaviour.
- What action should I take?
- Follow the official migration guide below, update affected call sites, run `dart fix --apply` where a fix is available, then run your tests.
Before and after (from the official guide)
| 1 | testWidgets('Indeterminate CircularProgressIndicator', (WidgetTester tester) async { | |
| 2 | final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); | |
| 3 | ||
| 4 | await tester.pumpFrames(animationSheet.record( | |
| 5 | const Directionality( | |
| 6 | textDirection: TextDirection.ltr, | |
| 7 | child: Padding( | |
| 8 | padding: EdgeInsets.all(4), | |
| 9 | child: CircularProgressIndicator(), | |
| 10 | ), | |
| 11 | ), | |
| 12 | ), const Duration(seconds: 2)); | |
| 13 | ||
| 14 | − | // The code starting here needs migration. |
| 15 | − | |
| 16 | − | tester.binding.setSurfaceSize(animationSheet.sheetSize()); |
| 17 | − | |
| 18 | − | final Widget display = await animationSheet.display(); |
| 19 | − | await tester.pumpWidget(display); |
| 20 | − | |
| 21 | await expectLater( | |
| 22 | − | find.byWidget(display), |
| 23 | matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'), | |
| 24 | ); | |
| 25 | }, skip: isBrowser); // https://github.com/flutter/flutter/issues/42767 |
| 1 | testWidgets('Indeterminate CircularProgressIndicator', (WidgetTester tester) async { | |
| 2 | final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); | |
| 3 | ||
| 4 | await tester.pumpFrames(animationSheet.record( | |
| 5 | const Directionality( | |
| 6 | textDirection: TextDirection.ltr, | |
| 7 | child: Padding( | |
| 8 | padding: EdgeInsets.all(4), | |
| 9 | child: CircularProgressIndicator(), | |
| 10 | ), | |
| 11 | ), | |
| 12 | ), const Duration(seconds: 2)); | |
| 13 | ||
| 14 | await expectLater( | |
| 15 | + | animationSheet.collate(20), |
| 16 | matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'), | |
| 17 | ); | |
| 18 | }, skip: isBrowser); // https://github.com/flutter/flutter/issues/42767 |
Raw before / after
testWidgets('Indeterminate CircularProgressIndicator', (WidgetTester tester) async {
final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40));
await tester.pumpFrames(animationSheet.record(
const Directionality(
textDirection: TextDirection.ltr,
child: Padding(
padding: EdgeInsets.all(4),
child: CircularProgressIndicator(),
),
),
), const Duration(seconds: 2));
// The code starting here needs migration.
tester.binding.setSurfaceSize(animationSheet.sheetSize());
final Widget display = await animationSheet.display();
await tester.pumpWidget(display);
await expectLater(
find.byWidget(display),
matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'),
);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/42767testWidgets('Indeterminate CircularProgressIndicator', (WidgetTester tester) async {
final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40));
await tester.pumpFrames(animationSheet.record(
const Directionality(
textDirection: TextDirection.ltr,
child: Padding(
padding: EdgeInsets.all(4),
child: CircularProgressIndicator(),
),
),
), const Duration(seconds: 2));
await expectLater(
animationSheet.collate(20),
matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'),
);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/42767Official migration guide (excerpt, © The Flutter Authors, CC BY 3.0)
To migrate to the new API, change the process of setting
surface size and displaying the widget into
[AnimationSheetBuilder.collate][].
Derive cells per row
The collate requires an explicit cellsPerRow
argument, which is the number of frames per
row in the output image. It can be manually counted,
or calculated as follows:
- Find the width of frame, specified when constructing
AnimationSheetBuilder. For example, in the following snippet it's 80:
final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(80, 30));- Find the width of surface size, specified when setting the surface size; the default is 800. For example, in the following snippet it's 600:
tester.binding.setSurfaceSize(animationSheet.sheetSize(600));- The frames per row should be the result of the two numbers divided, rounded down. For example, 600 / 80 = 7 (rounded down), therefore
animationSheet.collate(7)Migrate code
Code before migration:
testWidgets('Indeterminate CircularProgressIndicator', (WidgetTester tester) async {
final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40));
await tester.pumpFrames(animationSheet.record(
const Directionality(
textDirection: TextDirection.ltr,
child: Padding(
padding: EdgeInsets.all(4),
child: CircularProgressIndicator(),
),
),
), const Duration(seconds: 2));
// The code starting here needs migration.
tester.binding.setSurfaceSize(animationSheet.sheetSize());
final Widget display = await animationSheet.display();
await tester.pumpWidget(display);
await expectLater(
find.byWidget(display),
matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'),
);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/42767Code after migration (cellsPerRow is 20, derived from 800 / 40):
testWidgets('Indeterminate CircularProgressIndicator', (WidgetTester tester) async {
final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40));
await tester.pumpFrames(animationSheet.record(
const Directionality(
textDirection: TextDirection.ltr,
child: Padding(
padding: EdgeInsets.all(4),
child: CircularProgressIndicator(),
),
),
), const Duration(seconds: 2));
await expectLater(
animationSheet.collate(20),
matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'),
);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/42767It's expected that related golden test reference images are invalidated, which should all be updated. The new images should be identical to the old ones except 1/3 in scale.
AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.Listed in the official breaking-changes index (docs.flutter.dev/release/breaking-changes).
An official announcement or migration guide documents an intended behaviour or API change. A verified source change (git diff) shows code changed but does not by itself prove a public API is breaking. AI interpretations are labelled and never used to classify a change.
- Official migration guide
- AnimationSheetBuilder
- AnimationSheetBuilder.collate
- Test WidgetTester handling test pointers
- Source commit
- b3045439b7c0
- Source last updated
- Oct 21, 2026
- Last synchronized
- Oct 21, 2026
- Publication status
- published
Publication history
- Oct 21, 2026, 8:31 PM: new → published (ingestion) — Backed by an official breaking-change/migration guide.
AI_PROVIDER (for example to openai-compatible with a local Ollama or LM Studio endpoint) to enable grounded explanations. Everything else on this page works without an AI provider.