Skip to content

Commit 3f5bd7d

Browse files
authored
Add Material 3 AppBar example (#102823)
1 parent 348a2b4 commit 3f5bd7d

File tree

9 files changed

+295
-44
lines changed

9 files changed

+295
-44
lines changed

examples/api/lib/material/app_bar/app_bar.0.dart

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,21 @@
66

77
import 'package:flutter/material.dart';
88

9-
void main() => runApp(const MyApp());
9+
void main() => runApp(const AppBarApp());
1010

11-
class MyApp extends StatelessWidget {
12-
const MyApp({super.key});
13-
14-
static const String _title = 'Flutter Code Sample';
11+
class AppBarApp extends StatelessWidget {
12+
const AppBarApp({super.key});
1513

1614
@override
1715
Widget build(BuildContext context) {
1816
return const MaterialApp(
19-
title: _title,
20-
home: MyStatelessWidget(),
17+
home: AppBarExample(),
2118
);
2219
}
2320
}
2421

25-
class MyStatelessWidget extends StatelessWidget {
26-
const MyStatelessWidget({super.key});
22+
class AppBarExample extends StatelessWidget {
23+
const AppBarExample({super.key});
2724

2825
@override
2926
Widget build(BuildContext context) {

examples/api/lib/material/app_bar/app_bar.1.dart

Lines changed: 99 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,120 @@
66

77
import 'package:flutter/material.dart';
88

9-
void main() => runApp(const MyApp());
9+
final List<int> _items = List<int>.generate(51, (int index) => index);
1010

11-
class MyApp extends StatelessWidget {
12-
const MyApp({super.key});
11+
void main() => runApp(const AppBarApp());
1312

14-
static const String _title = 'Flutter Code Sample';
13+
class AppBarApp extends StatelessWidget {
14+
const AppBarApp({super.key});
1515

1616
@override
1717
Widget build(BuildContext context) {
18-
return const MaterialApp(
19-
title: _title,
20-
home: MyStatelessWidget(),
18+
return MaterialApp(
19+
theme: ThemeData(
20+
colorSchemeSeed: const Color(0xff6750a4),
21+
useMaterial3: true,
22+
),
23+
home: const AppBarExample(),
2124
);
2225
}
2326
}
2427

25-
class MyStatelessWidget extends StatelessWidget {
26-
const MyStatelessWidget({super.key});
28+
class AppBarExample extends StatefulWidget {
29+
const AppBarExample({super.key});
30+
31+
@override
32+
State<AppBarExample> createState() => _AppBarExampleState();
33+
}
34+
35+
class _AppBarExampleState extends State<AppBarExample> {
36+
bool shadowColor = false;
37+
double? scrolledUnderElevation;
2738

2839
@override
2940
Widget build(BuildContext context) {
30-
final ButtonStyle style =
31-
TextButton.styleFrom(primary: Theme.of(context).colorScheme.onPrimary);
41+
final ColorScheme colorScheme = Theme.of(context).colorScheme;
42+
final Color oddItemColor = colorScheme.primary.withOpacity(0.05);
43+
final Color evenItemColor = colorScheme.primary.withOpacity(0.15);
44+
3245
return Scaffold(
3346
appBar: AppBar(
34-
actions: <Widget>[
35-
TextButton(
36-
style: style,
37-
onPressed: () {},
38-
child: const Text('Action 1'),
39-
),
40-
TextButton(
41-
style: style,
42-
onPressed: () {},
43-
child: const Text('Action 2'),
47+
title: const Text('AppBar Demo'),
48+
scrolledUnderElevation: scrolledUnderElevation,
49+
shadowColor: shadowColor ? Theme.of(context).colorScheme.shadow : null,
50+
),
51+
body: GridView.builder(
52+
shrinkWrap: true,
53+
itemCount: _items.length,
54+
padding: const EdgeInsets.all(8.0),
55+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
56+
crossAxisCount: 3,
57+
childAspectRatio: 2.0,
58+
mainAxisSpacing: 10.0,
59+
crossAxisSpacing: 10.0,
60+
),
61+
itemBuilder: (BuildContext context, int index) {
62+
if (index == 0) {
63+
return Center(
64+
child: Text(
65+
'Scroll to see the Appbar in effect.',
66+
style: Theme.of(context).textTheme.labelLarge,
67+
textAlign: TextAlign.center,
68+
),
69+
);
70+
}
71+
return Container(
72+
alignment: Alignment.center,
73+
// tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
74+
decoration: BoxDecoration(
75+
borderRadius: BorderRadius.circular(20.0),
76+
color: _items[index].isOdd ? oddItemColor : evenItemColor,
77+
),
78+
child: Text('Item $index'),
79+
);
80+
},
81+
),
82+
bottomNavigationBar: BottomAppBar(
83+
child: Padding(
84+
padding: const EdgeInsets.all(8),
85+
child: OverflowBar(
86+
overflowAlignment: OverflowBarAlignment.center,
87+
alignment: MainAxisAlignment.center,
88+
overflowSpacing: 5.0,
89+
children: <Widget>[
90+
ElevatedButton.icon(
91+
onPressed: () {
92+
setState(() {
93+
shadowColor = !shadowColor;
94+
});
95+
},
96+
icon: Icon(
97+
shadowColor ? Icons.visibility_off : Icons.visibility,
98+
),
99+
label: const Text('shadow color'),
100+
),
101+
const SizedBox(width: 5),
102+
ElevatedButton.icon(
103+
onPressed: () {
104+
if (scrolledUnderElevation == null) {
105+
setState(() {
106+
// Default elevation is 3.0, increment by 1.0.
107+
scrolledUnderElevation = 4.0;
108+
});
109+
} else {
110+
setState(() {
111+
scrolledUnderElevation = scrolledUnderElevation! + 1.0;
112+
});
113+
}
114+
},
115+
icon: const Icon(Icons.add),
116+
label: Text(
117+
'scrolledUnderElevation: ${scrolledUnderElevation ?? 'default'}',
118+
),
119+
),
120+
],
44121
),
45-
],
122+
),
46123
),
47124
);
48125
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2014 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+
// Flutter code sample for AppBar
6+
7+
import 'package:flutter/material.dart';
8+
9+
void main() => runApp(const AppBarApp());
10+
11+
class AppBarApp extends StatelessWidget {
12+
const AppBarApp({super.key});
13+
14+
@override
15+
Widget build(BuildContext context) {
16+
return const MaterialApp(
17+
home: AppBarExample(),
18+
);
19+
}
20+
}
21+
22+
class AppBarExample extends StatelessWidget {
23+
const AppBarExample({super.key});
24+
25+
@override
26+
Widget build(BuildContext context) {
27+
final ButtonStyle style = TextButton.styleFrom(
28+
primary: Theme.of(context).colorScheme.onPrimary,
29+
);
30+
return Scaffold(
31+
appBar: AppBar(
32+
actions: <Widget>[
33+
TextButton(
34+
style: style,
35+
onPressed: () {},
36+
child: const Text('Action 1'),
37+
),
38+
TextButton(
39+
style: style,
40+
onPressed: () {},
41+
child: const Text('Action 2'),
42+
),
43+
],
44+
),
45+
);
46+
}
47+
}

examples/api/lib/material/app_bar/sliver_app_bar.1.dart

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,27 @@
66

77
import 'package:flutter/material.dart';
88

9-
void main() => runApp(const MyApp());
9+
void main() => runApp(const AppBarApp());
1010

11-
class MyApp extends StatelessWidget {
12-
const MyApp({super.key});
13-
14-
static const String _title = 'Flutter Code Sample';
11+
class AppBarApp extends StatelessWidget {
12+
const AppBarApp({super.key});
1513

1614
@override
1715
Widget build(BuildContext context) {
1816
return const MaterialApp(
19-
title: _title,
20-
home: MyStatefulWidget(),
17+
home: SliverAppBarExample(),
2118
);
2219
}
2320
}
2421

25-
class MyStatefulWidget extends StatefulWidget {
26-
const MyStatefulWidget({super.key});
22+
class SliverAppBarExample extends StatefulWidget {
23+
const SliverAppBarExample({super.key});
2724

2825
@override
29-
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
26+
State<SliverAppBarExample> createState() => _SliverAppBarExampleState();
3027
}
3128

32-
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
29+
class _SliverAppBarExampleState extends State<SliverAppBarExample> {
3330
bool _pinned = true;
3431
bool _snap = false;
3532
bool _floating = false;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2014 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:flutter/material.dart';
6+
import 'package:flutter_api_samples/material/app_bar/app_bar.0.dart' as example;
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
void main() {
10+
testWidgets('Appbar updates on navigation', (WidgetTester tester) async {
11+
await tester.pumpWidget(
12+
const example.AppBarApp(),
13+
);
14+
15+
expect(find.widgetWithText(AppBar, 'AppBar Demo'), findsOneWidget);
16+
expect(find.text('This is the home page'), findsOneWidget);
17+
18+
await tester.tap(find.byIcon(Icons.navigate_next));
19+
await tester.pumpAndSettle();
20+
21+
expect(find.widgetWithText(AppBar, 'Next page'), findsOneWidget);
22+
expect(find.text('This is the next page'), findsOneWidget);
23+
});
24+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2014 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:flutter/material.dart';
6+
import 'package:flutter_api_samples/material/app_bar/app_bar.1.dart' as example;
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
const Offset _kOffset = Offset(0.0, -100.0);
10+
11+
void main() {
12+
testWidgets('Appbar Material 3 test', (WidgetTester tester) async {
13+
await tester.pumpWidget(
14+
const example.AppBarApp()
15+
);
16+
17+
expect(find.widgetWithText(AppBar, 'AppBar Demo'), findsOneWidget);
18+
Material appbarMaterial = _getAppBarMaterial(tester);
19+
expect(appbarMaterial.shadowColor, null);
20+
expect(appbarMaterial.elevation, 0);
21+
22+
await tester.drag(find.text('Item 4'), _kOffset, touchSlopY: 0, warnIfMissed: false);
23+
24+
await tester.pump();
25+
await tester.pump(const Duration(milliseconds: 500));
26+
27+
await tester.tap(find.text('shadow color'));
28+
await tester.pumpAndSettle();
29+
appbarMaterial = _getAppBarMaterial(tester);
30+
expect(appbarMaterial.shadowColor, Colors.black);
31+
expect(appbarMaterial.elevation, 3.0);
32+
33+
await tester.tap(find.text('scrolledUnderElevation: default'));
34+
await tester.pumpAndSettle();
35+
36+
appbarMaterial = _getAppBarMaterial(tester);
37+
expect(appbarMaterial.shadowColor, Colors.black);
38+
expect(appbarMaterial.elevation, 4.0);
39+
40+
await tester.tap(find.text('scrolledUnderElevation: 4.0'));
41+
await tester.pumpAndSettle();
42+
appbarMaterial = _getAppBarMaterial(tester);
43+
expect(appbarMaterial.shadowColor, Colors.black);
44+
expect(appbarMaterial.elevation, 5.0);
45+
});
46+
}
47+
48+
Material _getAppBarMaterial(WidgetTester tester) {
49+
return tester.widget<Material>(
50+
find.descendant(
51+
of: find.byType(AppBar),
52+
matching: find.byType(Material),
53+
),
54+
);
55+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2014 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:flutter/material.dart';
6+
import 'package:flutter_api_samples/material/app_bar/app_bar.2.dart' as example;
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
void main() {
10+
testWidgets('Appbar and actions', (WidgetTester tester) async {
11+
await tester.pumpWidget(
12+
const example.AppBarApp(),
13+
);
14+
15+
expect(find.byType(AppBar), findsOneWidget);
16+
expect(find.widgetWithText(TextButton, 'Action 1'), findsOneWidget);
17+
expect(find.widgetWithText(TextButton, 'Action 2'), findsOneWidget);
18+
});
19+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2014 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:flutter/material.dart';
6+
import 'package:flutter_api_samples/material/app_bar/sliver_app_bar.1.dart' as example;
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
const Offset _kOffset = Offset(0.0, -200.0);
10+
11+
void main() {
12+
testWidgets('SliverAppbar can be pinned', (WidgetTester tester) async {
13+
await tester.pumpWidget(
14+
const example.AppBarApp(),
15+
);
16+
17+
expect(find.widgetWithText(SliverAppBar, 'SliverAppBar'), findsOneWidget);
18+
expect(tester.getBottomLeft(find.text('SliverAppBar')).dy, 144.0);
19+
20+
await tester.drag(find.text('0'), _kOffset, touchSlopY: 0, warnIfMissed: false);
21+
await tester.pump();
22+
await tester.pump(const Duration(milliseconds: 500));
23+
expect(tester.getBottomLeft(find.text('SliverAppBar')).dy, 40.0);
24+
});
25+
}

0 commit comments

Comments
 (0)