[英]How to use BottomNavigationBar with Navigator?
The Flutter Gallery example of BottomNavigationBar
uses a Stack
of FadeTransitions
in the body of the Scaffold
. BottomNavigationBar 的
FadeTransitions
Gallery 示例在Scaffold
的主体中使用了BottomNavigationBar
Stack
。
I feel it would be cleaner (and easier to animate) if we could switch pages by using a Navigator
.我觉得如果我们可以使用
Navigator
来切换页面会更干净(也更容易制作动画)。
Are there any examples of this?有这方面的例子吗?
int index = 0;
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Stack(
children: <Widget>[
new Offstage(
offstage: index != 0,
child: new TickerMode(
enabled: index == 0,
child: new MaterialApp(home: new YourLeftPage()),
),
),
new Offstage(
offstage: index != 1,
child: new TickerMode(
enabled: index == 1,
child: new MaterialApp(home: new YourRightPage()),
),
),
],
),
bottomNavigationBar: new BottomNavigationBar(
currentIndex: index,
onTap: (int index) { setState((){ this.index = index; }); },
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text("Left"),
),
new BottomNavigationBarItem(
icon: new Icon(Icons.search),
title: new Text("Right"),
),
],
),
);
}
You should keep each page by Stack
to keep their state.您应该通过
Stack
保留每个页面以保持其状态。 Offstage
stops painting, TickerMode
stops animation. Offstage
停止绘画, TickerMode
停止动画。 MaterialApp
includes Navigator
. MaterialApp
包括Navigator
。
Output:输出:
Code:代码:
int _index = 0;
@override
Widget build(BuildContext context) {
Widget child;
switch (_index) {
case 0:
child = FlutterLogo();
break;
case 1:
child = FlutterLogo(colors: Colors.orange);
break;
case 2:
child = FlutterLogo(colors: Colors.red);
break;
}
return Scaffold(
body: SizedBox.expand(child: child),
bottomNavigationBar: BottomNavigationBar(
onTap: (newIndex) => setState(() => _index = newIndex),
currentIndex: _index,
items: [
BottomNavigationBarItem(icon: Icon(Icons.looks_one), title: Text("Blue")),
BottomNavigationBarItem(icon: Icon(Icons.looks_two), title: Text("Orange")),
BottomNavigationBarItem(icon: Icon(Icons.looks_3), title: Text("Red")),
],
),
);
}
The Complete Example完整示例
First make a class MyBottomBarDemo
首先创建一个类
MyBottomBarDemo
class MyBottomBarDemo extends StatefulWidget {
@override
_MyBottomBarDemoState createState() => new _MyBottomBarDemoState();
}
class _MyBottomBarDemoState extends State<MyBottomBarDemo> {
int _pageIndex = 0;
PageController _pageController;
List<Widget> tabPages = [
Screen1(),
Screen2(),
Screen3(),
];
@override
void initState(){
super.initState();
_pageController = PageController(initialPage: _pageIndex);
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("BottomNavigationBar", style: TextStyle(color: Colors.white)),
backgroundColor: Colors.deepPurple,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _pageIndex,
onTap: onTabTapped,
backgroundColor: Colors.white,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem( icon: Icon(Icons.home), title: Text("Home")),
BottomNavigationBarItem(icon: Icon(Icons.mail), title: Text("Messages")),
BottomNavigationBarItem(icon: Icon(Icons.person), title: Text("Profile")),
],
),
body: PageView(
children: tabPages,
onPageChanged: onPageChanged,
controller: _pageController,
),
);
}
void onPageChanged(int page) {
setState(() {
this._pageIndex = page;
});
}
void onTabTapped(int index) {
this._pageController.animateToPage(index,duration: const Duration(milliseconds: 500),curve: Curves.easeInOut);
}
}
Then create a your screens然后创建一个你的屏幕
class Screen1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: Center(child: Text("Screen 1")),
);
}
}
class Screen2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
child: Center(child: Text("Screen 2")),
);
}
}
class Screen3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.cyan,
child: Center(child: Text("Screen 3")),
);
}
}
Here is an example how you can use Navigator with BottomNavigationBar to navigate different screen.下面是一个如何使用 Navigator 和 BottomNavigationBar 来导航不同屏幕的示例。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// This navigator state will be used to navigate different pages
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
int _currentTabIndex = 0;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Navigator(key: _navigatorKey, onGenerateRoute: generateRoute),
bottomNavigationBar: _bottomNavigationBar(),
),
);
}
Widget _bottomNavigationBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text("Home"),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle), title: Text("Account")),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
title: Text("Settings"),
)
],
onTap: _onTap,
currentIndex: _currentTabIndex,
);
}
_onTap(int tabIndex) {
switch (tabIndex) {
case 0:
_navigatorKey.currentState.pushReplacementNamed("Home");
break;
case 1:
_navigatorKey.currentState.pushReplacementNamed("Account");
break;
case 2:
_navigatorKey.currentState.pushReplacementNamed("Settings");
break;
}
setState(() {
_currentTabIndex = tabIndex;
});
}
Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case "Account":
return MaterialPageRoute(builder: (context) => Container(color: Colors.blue,child: Center(child: Text("Account"))));
case "Settings":
return MaterialPageRoute(builder: (context) => Container(color: Colors.green,child: Center(child: Text("Settings"))));
default:
return MaterialPageRoute(builder: (context) => Container(color: Colors.white,child: Center(child: Text("Home"))));
}
}
}
Here is example:这是示例:
int _currentIndex = 0;
Route<Null> _getRoute(RouteSettings settings) {
final initialSettings = new RouteSettings(
name: settings.name,
isInitialRoute: true);
return new MaterialPageRoute<Null>(
settings: initialSettings,
builder: (context) =>
new Scaffold(
body: new Center(
child: new Container(
height: 200.0,
width: 200.0,
child: new Column(children: <Widget>[
new Text(settings.name),
new FlatButton(onPressed: () =>
Navigator.of(context).pushNamed(
"${settings.name}/next"), child: new Text("push")),
],
))
),
bottomNavigationBar: new BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (value) {
final routes = ["/list", "/map"];
_currentIndex = value;
Navigator.of(context).pushNamedAndRemoveUntil(
routes[value], (route) => false);
},
items: [
new BottomNavigationBarItem(
icon: new Icon(Icons.list), title: new Text("List")),
new BottomNavigationBarItem(
icon: new Icon(Icons.map), title: new Text("Map")),
]),
));
}
@override
Widget build(BuildContext context) =>
new MaterialApp(
initialRoute: "/list",
onGenerateRoute: _getRoute,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
);
You can set isInitialRoute to true and pass it to MaterialPageRoute.您可以将isInitialRoute设置为 true 并将其传递给 MaterialPageRoute。 It will remove pop animation.
它将删除流行动画。
And to remove old routes you can use pushNamedAndRemoveUntil要删除旧路由,您可以使用pushNamedAndRemoveUntil
Navigator.of(context).pushNamedAndRemoveUntil(routes[value], (route) => false);
To set current page you can have a variable in your state _currentIndex
and assign it to BottomNavigationBar :要设置当前页面,您可以在状态
_currentIndex
有一个变量并将其分配给BottomNavigationBar :
Navigator.of(context).pushNamedAndRemoveUntil(
routes[value], (route) => true);
I had to use true to enable back button.我必须使用 true 才能启用后退按钮。
NB: I was using Navigator.pushNamed()
for navigation.注意:我使用
Navigator.pushNamed()
进行导航。
This is the code I am using in my project.这是我在项目中使用的代码。 If you try to avoid page viewer so you can try this
如果您尝试避免使用页面查看器,那么您可以试试这个
import 'package:flutter/material.dart';
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
@override
State<Dashboard> createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
int _selectedIndex = 0;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample'),
),
body: SingleChildScrollView(
child: Column(
children: [
if (_selectedIndex == 0)
// you can call custom widget here
Column(
children: const [
Text("0"),
],
)
else if (_selectedIndex == 1)
Column(
children: const [
Text("1"),
],
)
else
Column(
children: const [
Text("2"),
],
),
],
),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.headphones),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
unselectedItemColor: Colors.grey,
onTap: _onItemTapped,
),
);
}
}
Happy Coding快乐编码
Glad You asked, I experimented with this a couple of months back and tried to simplify this through a blog post.很高兴你问,几个月前我尝试过这个,并试图通过一篇博客文章来简化它。 I won't be able to post the complete code here since it is pretty long, But I can certainly link all the resources to clarify it.
我将无法在此处发布完整的代码,因为它很长,但我当然可以链接所有资源以澄清它。
Here's the resulting output of what the article helps you build这是本文帮助您构建的结果 output
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.