Flutter App 中每个页面的多个脚手架
Multiple Scaffolds for each page inside a Flutter App
API 文档:https://api.flutter.dev/flutter/material/Scaffold-class.html 说:
The Scaffold was designed to be the single top level container for a
MaterialApp and it's typically not necessary to nest scaffolds. For
example in a tabbed UI, where the bottomNavigationBar is a TabBar and
the body is a TabBarView, you might be tempted to make each tab bar
view a scaffold with a differently titled AppBar. It would be better
to add a listener to the TabController that updates the AppBar.
是不是意味着Material App下只需要一个Scaffold,或者每个页面只有一个父Scaffold。如果是第一个,我们如何导航?如果晚了,是否意味着公共 AppBar
和 BottomBar
会在每次导航时重新呈现?最佳做法是什么。
这意味着,通常每个页面应该有一个Scaffold
(更准确地说,每个Route
/screen),并且你不应该嵌套Scaffold
s .
在屏幕之间导航
例如,看一下您可以在 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/screens,每个页面都有自己的Scaffold
。我们使用 Navigator
来回导航,因此我们的页面被添加到堆栈中,一个 Scaffold
在另一个之上。没关系。
If the it's later, doesn't it mean the common AppBar and BottomBar get re-rendered on each navigation?
是的,但这正是我们制作两个独立屏幕时想要的,每个屏幕都有自己的 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
.
的主体内导航
结论
作为一般经验法则:每个 Route
/屏幕仅使用一个 Scaffold
。仅使用一个 Scaffold
和 TabController
或 IndexedStack
等小部件来导航单个屏幕主体内的内容。
API 文档:https://api.flutter.dev/flutter/material/Scaffold-class.html 说:
The Scaffold was designed to be the single top level container for a MaterialApp and it's typically not necessary to nest scaffolds. For example in a tabbed UI, where the bottomNavigationBar is a TabBar and the body is a TabBarView, you might be tempted to make each tab bar view a scaffold with a differently titled AppBar. It would be better to add a listener to the TabController that updates the AppBar.
是不是意味着Material App下只需要一个Scaffold,或者每个页面只有一个父Scaffold。如果是第一个,我们如何导航?如果晚了,是否意味着公共 AppBar
和 BottomBar
会在每次导航时重新呈现?最佳做法是什么。
这意味着,通常每个页面应该有一个Scaffold
(更准确地说,每个Route
/screen),并且你不应该嵌套Scaffold
s .
在屏幕之间导航
例如,看一下您可以在 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/screens,每个页面都有自己的Scaffold
。我们使用 Navigator
来回导航,因此我们的页面被添加到堆栈中,一个 Scaffold
在另一个之上。没关系。
If the it's later, doesn't it mean the common AppBar and BottomBar get re-rendered on each navigation?
是的,但这正是我们制作两个独立屏幕时想要的,每个屏幕都有自己的 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
.
结论
作为一般经验法则:每个 Route
/屏幕仅使用一个 Scaffold
。仅使用一个 Scaffold
和 TabController
或 IndexedStack
等小部件来导航单个屏幕主体内的内容。