blob: 04fbdedd34e56ca68b919748757b75724e294eea [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This sample demonstrates nested navigation in a bottom navigation bar.
import 'package:flutter/material.dart';
// There are three possible tabs.
enum _Tab {
home,
one,
two,
}
// Each tab has two possible pages.
enum _TabPage {
home,
one,
}
typedef _TabPageCallback = void Function(List<_TabPage> pages);
void main() => runApp(const NavigatorPopHandlerApp());
class NavigatorPopHandlerApp extends StatelessWidget {
const NavigatorPopHandlerApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/home',
routes: <String, WidgetBuilder>{
'/home': (BuildContext context) => const _BottomNavPage(
),
},
);
}
}
class _BottomNavPage extends StatefulWidget {
const _BottomNavPage();
@override
State<_BottomNavPage> createState() => _BottomNavPageState();
}
class _BottomNavPageState extends State<_BottomNavPage> {
_Tab _tab = _Tab.home;
final GlobalKey _tabHomeKey = GlobalKey();
final GlobalKey _tabOneKey = GlobalKey();
final GlobalKey _tabTwoKey = GlobalKey();
List<_TabPage> _tabHomePages = <_TabPage>[_TabPage.home];
List<_TabPage> _tabOnePages = <_TabPage>[_TabPage.home];
List<_TabPage> _tabTwoPages = <_TabPage>[_TabPage.home];
BottomNavigationBarItem _itemForPage(_Tab page) {
switch (page) {
case _Tab.home:
return const BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Go to Home',
);
case _Tab.one:
return const BottomNavigationBarItem(
icon: Icon(Icons.one_k),
label: 'Go to One',
);
case _Tab.two:
return const BottomNavigationBarItem(
icon: Icon(Icons.two_k),
label: 'Go to Two',
);
}
}
Widget _getPage(_Tab page) {
switch (page) {
case _Tab.home:
return _BottomNavTab(
key: _tabHomeKey,
title: 'Home Tab',
color: Colors.grey,
pages: _tabHomePages,
onChangedPages: (List<_TabPage> pages) {
setState(() {
_tabHomePages = pages;
});
},
);
case _Tab.one:
return _BottomNavTab(
key: _tabOneKey,
title: 'Tab One',
color: Colors.amber,
pages: _tabOnePages,
onChangedPages: (List<_TabPage> pages) {
setState(() {
_tabOnePages = pages;
});
},
);
case _Tab.two:
return _BottomNavTab(
key: _tabTwoKey,
title: 'Tab Two',
color: Colors.blueGrey,
pages: _tabTwoPages,
onChangedPages: (List<_TabPage> pages) {
setState(() {
_tabTwoPages = pages;
});
},
);
}
}
void _onItemTapped(int index) {
setState(() {
_tab = _Tab.values.elementAt(index);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _getPage(_tab),
),
bottomNavigationBar: BottomNavigationBar(
items: _Tab.values.map(_itemForPage).toList(),
currentIndex: _Tab.values.indexOf(_tab),
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
class _BottomNavTab extends StatefulWidget {
const _BottomNavTab({
super.key,
required this.color,
required this.onChangedPages,
required this.pages,
required this.title,
});
final Color color;
final _TabPageCallback onChangedPages;
final List<_TabPage> pages;
final String title;
@override
State<_BottomNavTab> createState() => _BottomNavTabState();
}
class _BottomNavTabState extends State<_BottomNavTab> {
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return NavigatorPopHandler(
onPop: () {
_navigatorKey.currentState?.maybePop();
},
child: Navigator(
key: _navigatorKey,
onPopPage: (Route<void> route, void result) {
if (!route.didPop(null)) {
return false;
}
widget.onChangedPages(<_TabPage>[
...widget.pages,
]..removeLast());
return true;
},
pages: widget.pages.map((_TabPage page) {
switch (page) {
case _TabPage.home:
return MaterialPage<void>(
child: _LinksPage(
title: 'Bottom nav - tab ${widget.title} - route $page',
backgroundColor: widget.color,
buttons: <Widget>[
TextButton(
onPressed: () {
widget.onChangedPages(<_TabPage>[
...widget.pages,
_TabPage.one,
]);
},
child: const Text('Go to another route in this nested Navigator'),
),
],
),
);
case _TabPage.one:
return MaterialPage<void>(
child: _LinksPage(
backgroundColor: widget.color,
title: 'Bottom nav - tab ${widget.title} - route $page',
buttons: <Widget>[
TextButton(
onPressed: () {
widget.onChangedPages(<_TabPage>[
...widget.pages,
]..removeLast());
},
child: const Text('Go back'),
),
],
),
);
}
}).toList(),
),
);
}
}
class _LinksPage extends StatelessWidget {
const _LinksPage ({
required this.backgroundColor,
this.buttons = const <Widget>[],
required this.title,
});
final Color backgroundColor;
final List<Widget> buttons;
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: backgroundColor,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(title),
...buttons,
],
),
),
);
}
}