API文档:https://api.flutter.dev/flutter/material/Scaffold-class.html说:
[脚手架被设计为用于MaterialApp,通常不需要嵌套支架。对于选项卡式UI中的示例,其中bottomNavigationBar是TabBar,主体是一个TabBarView,您可能很想制作每个选项卡栏查看带有不同标题的AppBar的脚手架。会更好向用于更新AppBar的TabController添加侦听器。
是否意味着在Material App下仅需要一个单一的Scaffold,或者每个页面只有一个单一的父Scaffold。如果是第一个,我们如何导航?如果是稍后的版本,这是否意味着在每次导航时都重新渲染通用的AppBar
和BottomBar
?最佳做法是什么。
这通常意味着每一页(更准确地说,每个Scaffold
/屏幕)应该有一个Route
,并且您不应该嵌套Scaffold
。
例如,查看可以在DartPad中运行的代码段:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: FirstRoute(),
));
}
class FirstRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: RaisedButton(
child: Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
),
),
);
}
}
class SecondRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
在这里,您可以看到有两个不同的页面/Route
s /屏幕,每个页面都有自己的Scaffold
。我们使用Navigator
来回导航,因此我们的页面被添加到堆栈中,其中一个Scaffold
位于另一个页面的顶部。很好。
如果是稍后的版本,是否不意味着在每个导航上都重新渲染通用的AppBar和BottomBar?
是,但这正是我们制作两个单独的屏幕,每个屏幕都有自己的Scaffold
时想要的。
另一方面,看这个例子:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: FirstRoute(),
));
}
class FirstRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Scaffold(
body: Center(
child: RaisedButton(
child: Text('Open route'),
onPressed: () {},
),
),
),
);
}
}
[这里,我们嵌套两个Scaffold
,并且如您所见,第二个应用程序栏被绘制在第一个应用程序栏的下方。对于选项卡式导航或嵌套式导航,这不是最佳方法。如果要在Scaffold
的正文中导航并根据内容更改应用栏,则首选使用TabControllers
,例如DefaultTabController
。看一下这个例子:
import 'package:flutter/material.dart';
void main() {
runApp(TabBarDemo());
}
class TabBarDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
title: Text('Tabs Demo'),
),
body: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
如您所见,我们只使用了一个Scaffold
,因为我们实际上只处理一个屏幕。碰巧我们想要显示内容页面并在Scaffold
的正文中导航。
作为一般的经验法则:每个Scaffold
/屏幕仅使用一个Route
。仅将一个Scaffold
与诸如TabController
或IndexedStack
之类的小部件一起使用才能浏览单个屏幕主体内的内容。
我建议您为应用程序使用Scaffold
和AppBar
共同的BottomBar
,并且当用户更改BottomBar
选项卡时,您必须管理Scaffold
的主体。
您可以使用多个标签来管理单个脚手架:
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _currentIndex;
List<Widget> _children;
@override
void initState() {
_currentIndex = 0;
_children = [
Screen1(),
Screen2(),
Screen3(),
Screen4(),
];
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: onTabTapped,
type: BottomNavigationBarType.fixed,
fixedColor: Colors.blue,
items: [
BottomNavigationBarItem(
title: Text("Screen 1"),
),
BottomNavigationBarItem(
title: Text("Screen 2"),
),
BottomNavigationBarItem(title: Text("Screen 3")),
BottomNavigationBarItem(title: Text("Screen 4")),
],
),
);
}
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
}