Skip to content

Commit 3479aab

Browse files
authored
Updated the nested navigation NavigationBar example (#137788)
Updated the NavigationBar API doc that describes examples/api/lib/material/navigation_bar/navigation_bar.2.dart and made some cosmetic changes to the example to improve its appearance in Material 3. Also did a little gratuitous reformatting. Fixes #136125
1 parent dca1f9e commit 3479aab

File tree

2 files changed

+86
-47
lines changed

2 files changed

+86
-47
lines changed

examples/api/lib/material/navigation_bar/navigation_bar.2.dart

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -32,33 +32,47 @@ class _HomeState extends State<Home> with TickerProviderStateMixin<Home> {
3232
int selectedIndex = 0;
3333

3434
AnimationController buildFaderController() {
35-
final AnimationController controller =
36-
AnimationController(vsync: this, duration: const Duration(milliseconds: 200));
37-
controller.addStatusListener((AnimationStatus status) {
38-
if (status == AnimationStatus.dismissed) {
39-
setState(() {}); // Rebuild unselected destinations offstage.
40-
}
41-
});
35+
final AnimationController controller = AnimationController(
36+
vsync: this,
37+
duration: const Duration(milliseconds: 300),
38+
);
39+
controller.addStatusListener(
40+
(AnimationStatus status) {
41+
if (status == AnimationStatus.dismissed) {
42+
setState(() {}); // Rebuild unselected destinations offstage.
43+
}
44+
},
45+
);
4246
return controller;
4347
}
4448

4549
@override
4650
void initState() {
4751
super.initState();
48-
navigatorKeys =
49-
List<GlobalKey<NavigatorState>>.generate(allDestinations.length, (int index) => GlobalKey()).toList();
50-
destinationFaders =
51-
List<AnimationController>.generate(allDestinations.length, (int index) => buildFaderController()).toList();
52+
53+
navigatorKeys = List<GlobalKey<NavigatorState>>.generate(
54+
allDestinations.length,
55+
(int index) => GlobalKey(),
56+
).toList();
57+
58+
destinationFaders = List<AnimationController>.generate(
59+
allDestinations.length,
60+
(int index) => buildFaderController(),
61+
).toList();
5262
destinationFaders[selectedIndex].value = 1.0;
53-
destinationViews = allDestinations.map((Destination destination) {
54-
return FadeTransition(
55-
opacity: destinationFaders[destination.index].drive(CurveTween(curve: Curves.fastOutSlowIn)),
56-
child: DestinationView(
57-
destination: destination,
58-
navigatorKey: navigatorKeys[destination.index],
59-
),
60-
);
61-
}).toList();
63+
64+
final CurveTween tween = CurveTween(curve: Curves.fastOutSlowIn);
65+
destinationViews = allDestinations.map<Widget>(
66+
(Destination destination) {
67+
return FadeTransition(
68+
opacity: destinationFaders[destination.index].drive(tween),
69+
child: DestinationView(
70+
destination: destination,
71+
navigatorKey: navigatorKeys[destination.index],
72+
),
73+
);
74+
},
75+
).toList();
6276
}
6377

6478
@override
@@ -81,20 +95,22 @@ class _HomeState extends State<Home> with TickerProviderStateMixin<Home> {
8195
top: false,
8296
child: Stack(
8397
fit: StackFit.expand,
84-
children: allDestinations.map((Destination destination) {
85-
final int index = destination.index;
86-
final Widget view = destinationViews[index];
87-
if (index == selectedIndex) {
88-
destinationFaders[index].forward();
89-
return Offstage(offstage: false, child: view);
90-
} else {
91-
destinationFaders[index].reverse();
92-
if (destinationFaders[index].isAnimating) {
93-
return IgnorePointer(child: view);
98+
children: allDestinations.map(
99+
(Destination destination) {
100+
final int index = destination.index;
101+
final Widget view = destinationViews[index];
102+
if (index == selectedIndex) {
103+
destinationFaders[index].forward();
104+
return Offstage(offstage: false, child: view);
105+
} else {
106+
destinationFaders[index].reverse();
107+
if (destinationFaders[index].isAnimating) {
108+
return IgnorePointer(child: view);
109+
}
110+
return Offstage(child: view);
94111
}
95-
return Offstage(child: view);
96-
}
97-
}).toList(),
112+
},
113+
).toList(),
98114
),
99115
),
100116
bottomNavigationBar: NavigationBar(
@@ -104,12 +120,14 @@ class _HomeState extends State<Home> with TickerProviderStateMixin<Home> {
104120
selectedIndex = index;
105121
});
106122
},
107-
destinations: allDestinations.map((Destination destination) {
108-
return NavigationDestination(
109-
icon: Icon(destination.icon, color: destination.color),
110-
label: destination.title,
111-
);
112-
}).toList(),
123+
destinations: allDestinations.map<NavigationDestination>(
124+
(Destination destination) {
125+
return NavigationDestination(
126+
icon: Icon(destination.icon, color: destination.color),
127+
label: destination.title,
128+
);
129+
},
130+
).toList(),
113131
),
114132
),
115133
);
@@ -148,6 +166,7 @@ class RootPage extends StatelessWidget {
148166
final TextStyle headlineSmall = Theme.of(context).textTheme.headlineSmall!;
149167
final ButtonStyle buttonStyle = ElevatedButton.styleFrom(
150168
backgroundColor: destination.color,
169+
foregroundColor: Colors.white,
151170
visualDensity: VisualDensity.comfortable,
152171
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
153172
textStyle: headlineSmall,
@@ -157,6 +176,7 @@ class RootPage extends StatelessWidget {
157176
appBar: AppBar(
158177
title: Text('${destination.title} RootPage - /'),
159178
backgroundColor: destination.color,
179+
foregroundColor: Colors.white,
160180
),
161181
backgroundColor: destination.color[50],
162182
body: Center(
@@ -236,15 +256,23 @@ class ListPage extends StatelessWidget {
236256
@override
237257
Widget build(BuildContext context) {
238258
const int itemCount = 50;
259+
final ColorScheme colorScheme = Theme.of(context).colorScheme;
239260
final ButtonStyle buttonStyle = OutlinedButton.styleFrom(
261+
shape: RoundedRectangleBorder(
262+
borderRadius: BorderRadius.circular(8),
263+
side: BorderSide(
264+
color: colorScheme.onSurface.withOpacity(0.12),
265+
),
266+
),
240267
foregroundColor: destination.color,
241-
fixedSize: const Size.fromHeight(128),
268+
fixedSize: const Size.fromHeight(64),
242269
textStyle: Theme.of(context).textTheme.headlineSmall,
243270
);
244271
return Scaffold(
245272
appBar: AppBar(
246273
title: Text('${destination.title} ListPage - /list'),
247274
backgroundColor: destination.color,
275+
foregroundColor: Colors.white,
248276
),
249277
backgroundColor: destination.color[50],
250278
body: SizedBox.expand(
@@ -256,7 +284,11 @@ class ListPage extends StatelessWidget {
256284
child: OutlinedButton(
257285
style: buttonStyle.copyWith(
258286
backgroundColor: MaterialStatePropertyAll<Color>(
259-
Color.lerp(destination.color[100], Colors.white, index / itemCount)!,
287+
Color.lerp(
288+
destination.color[100],
289+
Colors.white,
290+
index / itemCount
291+
)!,
260292
),
261293
),
262294
onPressed: () {
@@ -303,6 +335,7 @@ class _TextPageState extends State<TextPage> {
303335
appBar: AppBar(
304336
title: Text('${widget.destination.title} TextPage - /list/text'),
305337
backgroundColor: widget.destination.color,
338+
foregroundColor: Colors.white,
306339
),
307340
backgroundColor: widget.destination.color[50],
308341
body: Container(

packages/flutter/lib/src/material/navigation_bar.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,18 @@ const double _kIndicatorWidth = 64;
6262
/// {@end-tool}
6363
///
6464
/// {@tool dartpad}
65-
/// This example shows a [NavigationBar] as it is used within a [Scaffold]
66-
/// widget when there are nested navigators that provide local navigation. The
67-
/// [NavigationBar] has four [NavigationDestination] widgets with different
68-
/// color schemes. The [onDestinationSelected] callback changes the selected
69-
/// item's index and displays a corresponding page with its own local navigator
70-
/// in the body of a [Scaffold].
65+
/// This example shows a [NavigationBar] within a main [Scaffold]
66+
/// widget that's used to control the visibility of destination pages.
67+
/// Each destination has its own scaffold and a nested navigator that
68+
/// provides local navigation. The example's [NavigationBar] has four
69+
/// [NavigationDestination] widgets with different color schemes. Its
70+
/// [onDestinationSelected] callback changes the selected
71+
/// destination's index and displays a corresponding page with its own
72+
/// local navigator and scaffold - all within the body of the main
73+
/// scaffold. The destination pages are organized in a [Stack] and
74+
/// switching destinations fades out the current page and
75+
/// fades in the new one. Destinations that aren't visible or animating
76+
/// are kept [Offstage].
7177
///
7278
/// ** See code in examples/api/lib/material/navigation_bar/navigation_bar.2.dart **
7379
/// {@end-tool}

0 commit comments

Comments
 (0)