Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 0e98194

Browse files
authored
Add Material 3 support for BottomAppBar (#106525)
1 parent 3894a06 commit 0e98194

File tree

9 files changed

+619
-86
lines changed

9 files changed

+619
-86
lines changed

dev/tools/gen_defaults/bin/gen_defaults.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import 'dart:io';
2020
import 'package:gen_defaults/action_chip_template.dart';
2121
import 'package:gen_defaults/app_bar_template.dart';
2222
import 'package:gen_defaults/banner_template.dart';
23+
import 'package:gen_defaults/bottom_app_bar.dart';
2324
import 'package:gen_defaults/bottom_sheet_template.dart';
2425
import 'package:gen_defaults/button_template.dart';
2526
import 'package:gen_defaults/card_template.dart';
@@ -119,6 +120,7 @@ Future<void> main(List<String> args) async {
119120
ActionChipTemplate('Chip', '$materialLib/chip.dart', tokens).updateFile();
120121
ActionChipTemplate('ActionChip', '$materialLib/action_chip.dart', tokens).updateFile();
121122
AppBarTemplate('AppBar', '$materialLib/app_bar.dart', tokens).updateFile();
123+
BottomAppBarTemplate('BottomAppBar', '$materialLib/bottom_app_bar.dart', tokens).updateFile();
122124
BannerTemplate('Banner', '$materialLib/banner.dart', tokens).updateFile();
123125
BottomSheetTemplate('BottomSheet', '$materialLib/bottom_sheet.dart', tokens).updateFile();
124126
ButtonTemplate('md.comp.elevated-button', 'ElevatedButton', '$materialLib/elevated_button.dart', tokens).updateFile();
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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 'template.dart';
6+
7+
class BottomAppBarTemplate extends TokenTemplate {
8+
const BottomAppBarTemplate(super.blockName, super.fileName, super.tokens);
9+
10+
@override
11+
String generate() => '''
12+
// Generated version ${tokens["version"]}
13+
class _${blockName}DefaultsM3 extends BottomAppBarTheme {
14+
const _${blockName}DefaultsM3(this.context)
15+
: super(
16+
elevation: ${elevation('md.comp.bottom-app-bar.container')},
17+
height: ${tokens['md.comp.bottom-app-bar.container.height']},
18+
);
19+
20+
final BuildContext context;
21+
22+
@override
23+
Color? get color => ${componentColor('md.comp.bottom-app-bar.container')};
24+
25+
@override
26+
Color? get surfaceTintColor => ${componentColor('md.comp.bottom-app-bar.container.surface-tint-layer')};
27+
28+
@override
29+
NotchedShape? get shape => const AutomaticNotchedShape(${shape('md.comp.bottom-app-bar.container')});
30+
}
31+
''';
32+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
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 BottomAppBar with Material 3
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter/rendering.dart';
9+
10+
void main() {
11+
runApp(const BottomAppBarDemo());
12+
}
13+
14+
class BottomAppBarDemo extends StatefulWidget {
15+
const BottomAppBarDemo({super.key});
16+
17+
@override
18+
State createState() => _BottomAppBarDemoState();
19+
}
20+
21+
class _BottomAppBarDemoState extends State<BottomAppBarDemo> {
22+
static const List<Color> colors = <Color>[
23+
Colors.yellow,
24+
Colors.orange,
25+
Colors.pink,
26+
Colors.purple,
27+
Colors.cyan,
28+
];
29+
30+
static final List<Widget> items = List<Widget>.generate(
31+
colors.length,
32+
(int index) => Container(color: colors[index], height: 150.0),
33+
).reversed.toList();
34+
35+
late ScrollController _controller;
36+
bool _showFab = true;
37+
bool _isElevated = true;
38+
bool _isVisible = true;
39+
40+
FloatingActionButtonLocation get _fabLocation => _isVisible
41+
? FloatingActionButtonLocation.endContained
42+
: FloatingActionButtonLocation.endFloat;
43+
44+
void _listen() {
45+
final ScrollDirection direction = _controller.position.userScrollDirection;
46+
if (direction == ScrollDirection.forward) {
47+
_show();
48+
} else if (direction == ScrollDirection.reverse) {
49+
_hide();
50+
}
51+
}
52+
53+
void _show() {
54+
if (!_isVisible) {
55+
setState(() => _isVisible = true);
56+
}
57+
}
58+
59+
void _hide() {
60+
if (_isVisible) {
61+
setState(() => _isVisible = false);
62+
}
63+
}
64+
65+
void _onShowFabChanged(bool value) {
66+
setState(() {
67+
_showFab = value;
68+
});
69+
}
70+
71+
void _onElevatedChanged(bool value) {
72+
setState(() {
73+
_isElevated = value;
74+
});
75+
}
76+
77+
void _addNewItem() {
78+
setState(() {
79+
items.insert(
80+
0,
81+
Container(color: colors[items.length % 5], height: 150.0),
82+
);
83+
});
84+
}
85+
86+
@override
87+
void initState() {
88+
super.initState();
89+
_controller = ScrollController();
90+
_controller.addListener(_listen);
91+
}
92+
93+
@override
94+
void dispose() {
95+
_controller.removeListener(_listen);
96+
_controller.dispose();
97+
super.dispose();
98+
}
99+
100+
@override
101+
Widget build(BuildContext context) {
102+
return MaterialApp(
103+
theme: ThemeData(useMaterial3: true),
104+
home: Scaffold(
105+
appBar: AppBar(
106+
title: const Text('Bottom App Bar Demo'),
107+
),
108+
body: Column(
109+
children: <Widget>[
110+
SwitchListTile(
111+
title: const Text('Floating Action Button'),
112+
value: _showFab,
113+
onChanged: _onShowFabChanged,
114+
),
115+
SwitchListTile(
116+
title: const Text('Bottom App Bar Elevation'),
117+
value: _isElevated,
118+
onChanged: _onElevatedChanged,
119+
),
120+
Expanded(
121+
child: ListView(
122+
controller: _controller,
123+
children: items.toList(),
124+
),
125+
),
126+
],
127+
),
128+
floatingActionButton: _showFab
129+
? FloatingActionButton(
130+
onPressed: _addNewItem,
131+
tooltip: 'Add New Item',
132+
elevation: _isVisible ? 0.0 : null,
133+
child: const Icon(Icons.add),
134+
)
135+
: null,
136+
floatingActionButtonLocation: _fabLocation,
137+
bottomNavigationBar: _DemoBottomAppBar(isElevated: _isElevated, isVisible: _isVisible),
138+
),
139+
);
140+
}
141+
}
142+
143+
class _DemoBottomAppBar extends StatelessWidget {
144+
const _DemoBottomAppBar({
145+
required this.isElevated,
146+
required this.isVisible,
147+
});
148+
149+
final bool isElevated;
150+
final bool isVisible;
151+
152+
@override
153+
Widget build(BuildContext context) {
154+
return AnimatedContainer(
155+
duration: const Duration(milliseconds: 200),
156+
height: isVisible ? 80.0 : 0,
157+
child: BottomAppBar(
158+
elevation: isElevated ? null : 0.0,
159+
child: Row(
160+
children: <Widget>[
161+
IconButton(
162+
tooltip: 'Open popup menu',
163+
icon: const Icon(Icons.more_vert),
164+
onPressed: () {
165+
final SnackBar snackBar = SnackBar(
166+
content: const Text('Yay! A SnackBar!'),
167+
action: SnackBarAction(
168+
label: 'Undo',
169+
onPressed: () {},
170+
),
171+
);
172+
173+
// Find the ScaffoldMessenger in the widget tree
174+
// and use it to show a SnackBar.
175+
ScaffoldMessenger.of(context).showSnackBar(snackBar);
176+
},
177+
),
178+
IconButton(
179+
tooltip: 'Search',
180+
icon: const Icon(Icons.search),
181+
onPressed: () {},
182+
),
183+
IconButton(
184+
tooltip: 'Favorite',
185+
icon: const Icon(Icons.favorite),
186+
onPressed: () {},
187+
),
188+
],
189+
),
190+
),
191+
);
192+
}
193+
}

0 commit comments

Comments
 (0)