[dynamic_layouts] Add a staggered grid layout example (#2559)

diff --git a/packages/dynamic_layouts/example/lib/main.dart b/packages/dynamic_layouts/example/lib/main.dart
index 5221ae6..18a2c20 100644
--- a/packages/dynamic_layouts/example/lib/main.dart
+++ b/packages/dynamic_layouts/example/lib/main.dart
@@ -4,6 +4,7 @@
 
 import 'package:flutter/material.dart';
 
+import 'staggered_layout_example.dart';
 import 'wrap_layout_example.dart';
 
 void main() {
@@ -28,7 +29,6 @@
 }
 
 /// The home page
-
 class MyHomePage extends StatelessWidget {
   /// The home page constructor.
   const MyHomePage({super.key});
@@ -52,6 +52,16 @@
               ),
               child: const Text('Wrap Demo'),
             ),
+            const SizedBox(height: 20),
+            ElevatedButton(
+              onPressed: () => Navigator.push(
+                context,
+                MaterialPageRoute<void>(
+                  builder: (BuildContext context) => const StaggeredExample(),
+                ),
+              ),
+              child: const Text('Staggered Demo'),
+            ),
           ],
         ),
       ),
diff --git a/packages/dynamic_layouts/example/lib/staggered_layout_example.dart b/packages/dynamic_layouts/example/lib/staggered_layout_example.dart
new file mode 100644
index 0000000..95b3020
--- /dev/null
+++ b/packages/dynamic_layouts/example/lib/staggered_layout_example.dart
@@ -0,0 +1,87 @@
+// Copyright 2013 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:dynamic_layouts/dynamic_layouts.dart';
+import 'package:flutter/material.dart';
+
+void main() {
+  runApp(const StaggeredExample());
+}
+
+/// A staggered layout example. Clicking the upper-right button will change
+/// between a grid with a fixed cross axis count and one with a main axis
+/// extent.
+class StaggeredExample extends StatefulWidget {
+  /// Creates a [StaggeredExample].
+  const StaggeredExample({super.key});
+
+  @override
+  State<StaggeredExample> createState() => _StaggeredExampleState();
+}
+
+class _StaggeredExampleState extends State<StaggeredExample> {
+  final List<Widget> children = List<Widget>.generate(
+    50,
+    (int index) => _DynamicSizedTile(index: index),
+  );
+
+  bool fixedCrossAxisCount = true;
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: const Text('Staggered Layout Example'),
+        actions: <Widget>[
+          Padding(
+            padding: const EdgeInsets.only(right: 50.0),
+            child: TextButton(
+              onPressed: () {
+                setState(() {
+                  fixedCrossAxisCount = !fixedCrossAxisCount;
+                });
+              },
+              child: Text(
+                fixedCrossAxisCount ? 'FIXED' : 'MAX',
+                style: const TextStyle(color: Colors.white),
+              ),
+            ),
+          ),
+        ],
+      ),
+      floatingActionButton: FloatingActionButton(
+        onPressed: () {
+          setState(() {
+            children.add(_DynamicSizedTile(index: children.length));
+          });
+        },
+        child: const Icon(Icons.plus_one),
+      ),
+      body: fixedCrossAxisCount
+          ? DynamicGridView.staggered(
+              crossAxisCount: 4,
+              children: <Widget>[...children],
+            )
+          : DynamicGridView.staggered(
+              maxCrossAxisExtent: 100,
+              children: <Widget>[...children],
+            ),
+    );
+  }
+}
+
+class _DynamicSizedTile extends StatelessWidget {
+  const _DynamicSizedTile({required this.index});
+
+  final int index;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      height: index % 3 * 50 + 20,
+      color: Colors.amber[(index % 8 + 1) * 100],
+      child: Text('Index $index'),
+    );
+  }
+}
diff --git a/packages/dynamic_layouts/example/test/staggered_example_test.dart b/packages/dynamic_layouts/example/test/staggered_example_test.dart
new file mode 100644
index 0000000..1b61dc6
--- /dev/null
+++ b/packages/dynamic_layouts/example/test/staggered_example_test.dart
@@ -0,0 +1,32 @@
+// Copyright 2013 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:example/staggered_layout_example.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  testWidgets('StaggeredExample lays out children correctly',
+      (WidgetTester tester) async {
+    tester.binding.window.physicalSizeTestValue = const Size(400, 200);
+    tester.binding.window.devicePixelRatioTestValue = 1.0;
+
+    await tester.pumpWidget(
+      const MaterialApp(
+        home: StaggeredExample(),
+      ),
+    );
+    await tester.pumpAndSettle();
+
+    expect(find.text('Index 0'), findsOneWidget);
+    expect(tester.getTopLeft(find.text('Index 0')), const Offset(0.0, 56.0));
+    expect(find.text('Index 8'), findsOneWidget);
+    expect(tester.getTopLeft(find.text('Index 8')), const Offset(100.0, 146.0));
+    expect(find.text('Index 10'), findsOneWidget);
+    expect(
+      tester.getTopLeft(find.text('Index 10')),
+      const Offset(200.0, 196.0),
+    );
+  });
+}