mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
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
This commit is contained in:
parent
dca1f9e5c8
commit
3479aaba75
@ -32,33 +32,47 @@ class _HomeState extends State<Home> with TickerProviderStateMixin<Home> {
|
|||||||
int selectedIndex = 0;
|
int selectedIndex = 0;
|
||||||
|
|
||||||
AnimationController buildFaderController() {
|
AnimationController buildFaderController() {
|
||||||
final AnimationController controller =
|
final AnimationController controller = AnimationController(
|
||||||
AnimationController(vsync: this, duration: const Duration(milliseconds: 200));
|
vsync: this,
|
||||||
controller.addStatusListener((AnimationStatus status) {
|
duration: const Duration(milliseconds: 300),
|
||||||
if (status == AnimationStatus.dismissed) {
|
);
|
||||||
setState(() {}); // Rebuild unselected destinations offstage.
|
controller.addStatusListener(
|
||||||
}
|
(AnimationStatus status) {
|
||||||
});
|
if (status == AnimationStatus.dismissed) {
|
||||||
|
setState(() {}); // Rebuild unselected destinations offstage.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
navigatorKeys =
|
|
||||||
List<GlobalKey<NavigatorState>>.generate(allDestinations.length, (int index) => GlobalKey()).toList();
|
navigatorKeys = List<GlobalKey<NavigatorState>>.generate(
|
||||||
destinationFaders =
|
allDestinations.length,
|
||||||
List<AnimationController>.generate(allDestinations.length, (int index) => buildFaderController()).toList();
|
(int index) => GlobalKey(),
|
||||||
|
).toList();
|
||||||
|
|
||||||
|
destinationFaders = List<AnimationController>.generate(
|
||||||
|
allDestinations.length,
|
||||||
|
(int index) => buildFaderController(),
|
||||||
|
).toList();
|
||||||
destinationFaders[selectedIndex].value = 1.0;
|
destinationFaders[selectedIndex].value = 1.0;
|
||||||
destinationViews = allDestinations.map((Destination destination) {
|
|
||||||
return FadeTransition(
|
final CurveTween tween = CurveTween(curve: Curves.fastOutSlowIn);
|
||||||
opacity: destinationFaders[destination.index].drive(CurveTween(curve: Curves.fastOutSlowIn)),
|
destinationViews = allDestinations.map<Widget>(
|
||||||
child: DestinationView(
|
(Destination destination) {
|
||||||
destination: destination,
|
return FadeTransition(
|
||||||
navigatorKey: navigatorKeys[destination.index],
|
opacity: destinationFaders[destination.index].drive(tween),
|
||||||
),
|
child: DestinationView(
|
||||||
);
|
destination: destination,
|
||||||
}).toList();
|
navigatorKey: navigatorKeys[destination.index],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -81,20 +95,22 @@ class _HomeState extends State<Home> with TickerProviderStateMixin<Home> {
|
|||||||
top: false,
|
top: false,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: allDestinations.map((Destination destination) {
|
children: allDestinations.map(
|
||||||
final int index = destination.index;
|
(Destination destination) {
|
||||||
final Widget view = destinationViews[index];
|
final int index = destination.index;
|
||||||
if (index == selectedIndex) {
|
final Widget view = destinationViews[index];
|
||||||
destinationFaders[index].forward();
|
if (index == selectedIndex) {
|
||||||
return Offstage(offstage: false, child: view);
|
destinationFaders[index].forward();
|
||||||
} else {
|
return Offstage(offstage: false, child: view);
|
||||||
destinationFaders[index].reverse();
|
} else {
|
||||||
if (destinationFaders[index].isAnimating) {
|
destinationFaders[index].reverse();
|
||||||
return IgnorePointer(child: view);
|
if (destinationFaders[index].isAnimating) {
|
||||||
|
return IgnorePointer(child: view);
|
||||||
|
}
|
||||||
|
return Offstage(child: view);
|
||||||
}
|
}
|
||||||
return Offstage(child: view);
|
},
|
||||||
}
|
).toList(),
|
||||||
}).toList(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: NavigationBar(
|
bottomNavigationBar: NavigationBar(
|
||||||
@ -104,12 +120,14 @@ class _HomeState extends State<Home> with TickerProviderStateMixin<Home> {
|
|||||||
selectedIndex = index;
|
selectedIndex = index;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
destinations: allDestinations.map((Destination destination) {
|
destinations: allDestinations.map<NavigationDestination>(
|
||||||
return NavigationDestination(
|
(Destination destination) {
|
||||||
icon: Icon(destination.icon, color: destination.color),
|
return NavigationDestination(
|
||||||
label: destination.title,
|
icon: Icon(destination.icon, color: destination.color),
|
||||||
);
|
label: destination.title,
|
||||||
}).toList(),
|
);
|
||||||
|
},
|
||||||
|
).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -148,6 +166,7 @@ class RootPage extends StatelessWidget {
|
|||||||
final TextStyle headlineSmall = Theme.of(context).textTheme.headlineSmall!;
|
final TextStyle headlineSmall = Theme.of(context).textTheme.headlineSmall!;
|
||||||
final ButtonStyle buttonStyle = ElevatedButton.styleFrom(
|
final ButtonStyle buttonStyle = ElevatedButton.styleFrom(
|
||||||
backgroundColor: destination.color,
|
backgroundColor: destination.color,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
visualDensity: VisualDensity.comfortable,
|
visualDensity: VisualDensity.comfortable,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||||
textStyle: headlineSmall,
|
textStyle: headlineSmall,
|
||||||
@ -157,6 +176,7 @@ class RootPage extends StatelessWidget {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('${destination.title} RootPage - /'),
|
title: Text('${destination.title} RootPage - /'),
|
||||||
backgroundColor: destination.color,
|
backgroundColor: destination.color,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
backgroundColor: destination.color[50],
|
backgroundColor: destination.color[50],
|
||||||
body: Center(
|
body: Center(
|
||||||
@ -236,15 +256,23 @@ class ListPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const int itemCount = 50;
|
const int itemCount = 50;
|
||||||
|
final ColorScheme colorScheme = Theme.of(context).colorScheme;
|
||||||
final ButtonStyle buttonStyle = OutlinedButton.styleFrom(
|
final ButtonStyle buttonStyle = OutlinedButton.styleFrom(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: BorderSide(
|
||||||
|
color: colorScheme.onSurface.withOpacity(0.12),
|
||||||
|
),
|
||||||
|
),
|
||||||
foregroundColor: destination.color,
|
foregroundColor: destination.color,
|
||||||
fixedSize: const Size.fromHeight(128),
|
fixedSize: const Size.fromHeight(64),
|
||||||
textStyle: Theme.of(context).textTheme.headlineSmall,
|
textStyle: Theme.of(context).textTheme.headlineSmall,
|
||||||
);
|
);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('${destination.title} ListPage - /list'),
|
title: Text('${destination.title} ListPage - /list'),
|
||||||
backgroundColor: destination.color,
|
backgroundColor: destination.color,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
backgroundColor: destination.color[50],
|
backgroundColor: destination.color[50],
|
||||||
body: SizedBox.expand(
|
body: SizedBox.expand(
|
||||||
@ -256,7 +284,11 @@ class ListPage extends StatelessWidget {
|
|||||||
child: OutlinedButton(
|
child: OutlinedButton(
|
||||||
style: buttonStyle.copyWith(
|
style: buttonStyle.copyWith(
|
||||||
backgroundColor: MaterialStatePropertyAll<Color>(
|
backgroundColor: MaterialStatePropertyAll<Color>(
|
||||||
Color.lerp(destination.color[100], Colors.white, index / itemCount)!,
|
Color.lerp(
|
||||||
|
destination.color[100],
|
||||||
|
Colors.white,
|
||||||
|
index / itemCount
|
||||||
|
)!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -303,6 +335,7 @@ class _TextPageState extends State<TextPage> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('${widget.destination.title} TextPage - /list/text'),
|
title: Text('${widget.destination.title} TextPage - /list/text'),
|
||||||
backgroundColor: widget.destination.color,
|
backgroundColor: widget.destination.color,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
backgroundColor: widget.destination.color[50],
|
backgroundColor: widget.destination.color[50],
|
||||||
body: Container(
|
body: Container(
|
||||||
|
@ -62,12 +62,18 @@ const double _kIndicatorWidth = 64;
|
|||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
///
|
///
|
||||||
/// {@tool dartpad}
|
/// {@tool dartpad}
|
||||||
/// This example shows a [NavigationBar] as it is used within a [Scaffold]
|
/// This example shows a [NavigationBar] within a main [Scaffold]
|
||||||
/// widget when there are nested navigators that provide local navigation. The
|
/// widget that's used to control the visibility of destination pages.
|
||||||
/// [NavigationBar] has four [NavigationDestination] widgets with different
|
/// Each destination has its own scaffold and a nested navigator that
|
||||||
/// color schemes. The [onDestinationSelected] callback changes the selected
|
/// provides local navigation. The example's [NavigationBar] has four
|
||||||
/// item's index and displays a corresponding page with its own local navigator
|
/// [NavigationDestination] widgets with different color schemes. Its
|
||||||
/// in the body of a [Scaffold].
|
/// [onDestinationSelected] callback changes the selected
|
||||||
|
/// destination's index and displays a corresponding page with its own
|
||||||
|
/// local navigator and scaffold - all within the body of the main
|
||||||
|
/// scaffold. The destination pages are organized in a [Stack] and
|
||||||
|
/// switching destinations fades out the current page and
|
||||||
|
/// fades in the new one. Destinations that aren't visible or animating
|
||||||
|
/// are kept [Offstage].
|
||||||
///
|
///
|
||||||
/// ** See code in examples/api/lib/material/navigation_bar/navigation_bar.2.dart **
|
/// ** See code in examples/api/lib/material/navigation_bar/navigation_bar.2.dart **
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
|
Loading…
Reference in New Issue
Block a user