Skip to content

Commit a1b59e7

Browse files
authored
[dynamic_layouts] Add a staggered grid layout example (#2559)
1 parent 33554ba commit a1b59e7

File tree

3 files changed

+130
-1
lines changed

3 files changed

+130
-1
lines changed

packages/dynamic_layouts/example/lib/main.dart

+11-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:flutter/material.dart';
66

7+
import 'staggered_layout_example.dart';
78
import 'wrap_layout_example.dart';
89

910
void main() {
@@ -28,7 +29,6 @@ class MyApp extends StatelessWidget {
2829
}
2930

3031
/// The home page
31-
3232
class MyHomePage extends StatelessWidget {
3333
/// The home page constructor.
3434
const MyHomePage({super.key});
@@ -52,6 +52,16 @@ class MyHomePage extends StatelessWidget {
5252
),
5353
child: const Text('Wrap Demo'),
5454
),
55+
const SizedBox(height: 20),
56+
ElevatedButton(
57+
onPressed: () => Navigator.push(
58+
context,
59+
MaterialPageRoute<void>(
60+
builder: (BuildContext context) => const StaggeredExample(),
61+
),
62+
),
63+
child: const Text('Staggered Demo'),
64+
),
5565
],
5666
),
5767
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:dynamic_layouts/dynamic_layouts.dart';
6+
import 'package:flutter/material.dart';
7+
8+
void main() {
9+
runApp(const StaggeredExample());
10+
}
11+
12+
/// A staggered layout example. Clicking the upper-right button will change
13+
/// between a grid with a fixed cross axis count and one with a main axis
14+
/// extent.
15+
class StaggeredExample extends StatefulWidget {
16+
/// Creates a [StaggeredExample].
17+
const StaggeredExample({super.key});
18+
19+
@override
20+
State<StaggeredExample> createState() => _StaggeredExampleState();
21+
}
22+
23+
class _StaggeredExampleState extends State<StaggeredExample> {
24+
final List<Widget> children = List<Widget>.generate(
25+
50,
26+
(int index) => _DynamicSizedTile(index: index),
27+
);
28+
29+
bool fixedCrossAxisCount = true;
30+
31+
@override
32+
Widget build(BuildContext context) {
33+
return Scaffold(
34+
appBar: AppBar(
35+
title: const Text('Staggered Layout Example'),
36+
actions: <Widget>[
37+
Padding(
38+
padding: const EdgeInsets.only(right: 50.0),
39+
child: TextButton(
40+
onPressed: () {
41+
setState(() {
42+
fixedCrossAxisCount = !fixedCrossAxisCount;
43+
});
44+
},
45+
child: Text(
46+
fixedCrossAxisCount ? 'FIXED' : 'MAX',
47+
style: const TextStyle(color: Colors.white),
48+
),
49+
),
50+
),
51+
],
52+
),
53+
floatingActionButton: FloatingActionButton(
54+
onPressed: () {
55+
setState(() {
56+
children.add(_DynamicSizedTile(index: children.length));
57+
});
58+
},
59+
child: const Icon(Icons.plus_one),
60+
),
61+
body: fixedCrossAxisCount
62+
? DynamicGridView.staggered(
63+
crossAxisCount: 4,
64+
children: <Widget>[...children],
65+
)
66+
: DynamicGridView.staggered(
67+
maxCrossAxisExtent: 100,
68+
children: <Widget>[...children],
69+
),
70+
);
71+
}
72+
}
73+
74+
class _DynamicSizedTile extends StatelessWidget {
75+
const _DynamicSizedTile({required this.index});
76+
77+
final int index;
78+
79+
@override
80+
Widget build(BuildContext context) {
81+
return Container(
82+
height: index % 3 * 50 + 20,
83+
color: Colors.amber[(index % 8 + 1) * 100],
84+
child: Text('Index $index'),
85+
);
86+
}
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:example/staggered_layout_example.dart';
6+
import 'package:flutter/material.dart';
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
void main() {
10+
testWidgets('StaggeredExample lays out children correctly',
11+
(WidgetTester tester) async {
12+
tester.binding.window.physicalSizeTestValue = const Size(400, 200);
13+
tester.binding.window.devicePixelRatioTestValue = 1.0;
14+
15+
await tester.pumpWidget(
16+
const MaterialApp(
17+
home: StaggeredExample(),
18+
),
19+
);
20+
await tester.pumpAndSettle();
21+
22+
expect(find.text('Index 0'), findsOneWidget);
23+
expect(tester.getTopLeft(find.text('Index 0')), const Offset(0.0, 56.0));
24+
expect(find.text('Index 8'), findsOneWidget);
25+
expect(tester.getTopLeft(find.text('Index 8')), const Offset(100.0, 146.0));
26+
expect(find.text('Index 10'), findsOneWidget);
27+
expect(
28+
tester.getTopLeft(find.text('Index 10')),
29+
const Offset(200.0, 196.0),
30+
);
31+
});
32+
}

0 commit comments

Comments
 (0)