我对Flutter项目的结构有疑问 .
目前结构如下:
带有bottomNavigationBar的主页包含多个选项卡,每个选项卡都是StatefulWidget,包含一些繁重的处理(远程API调用和数据显示) .
如果我从任何选项卡内部调用Navigator.pushNamed,则会发生以下情况:
-
正在后台重建所有选项卡(进行API调用等) .
-
新页面正常打开 .
-
当我按下后退按钮时,页面关闭,所有标签再次重建 .
因此,总共所有(每个选项卡)重建2次只是为了打开外部导航器页面 .
这是某种错误吗?完全不可理解为什么它在推出新路线之前完全重建bottomNavigationBar .
它应该如何工作:
-
当我从选项卡内部调用Navigator.pushNamed时,应该打开新页面,并且不应重建所有bottomNavigationBar选项卡并保持不变状态 .
-
当我按下时,页面应该关闭,用户返回到相同的bottomNavigationBar状态和它的选项卡,根本没有重建 .
这有可能实现吗?
这是代码:
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
int index = 0;
final _tab1 = new tab1(); //StatefulWidget, api calls, heavy data processing
final _tab2 = new tab2(); //StatefulWidget, api calls, heavy data processing
@override
Widget build(BuildContext context) {
debugPrint('homepage loaded:'+index.toString());
return new Scaffold(
body: new Stack(
children: <Widget>[
new Offstage(
offstage: index != 0,
child: new TickerMode(
enabled: index == 0,
child: _tab1,
),
),
new Offstage(
offstage: index != 1,
child: new TickerMode(
enabled: index == 1,
child: _tab2,
),
),
],
),
bottomNavigationBar: new BottomNavigationBar(
currentIndex: index,
type: BottomNavigationBarType.fixed,
onTap: (int index) { setState((){ this.index = index; }); },
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
icon: new Icon(Icons.live_help),
title: new Text("Tab1"),
),
new BottomNavigationBarItem(
icon: new Icon(Icons.favorite_border),
title: new Text("Tab 2"),
),
],
),
);
}
}
这是单个标签代码:
class tab1 extends StatefulWidget {
@override
tab1State createState() => new tab1State();
}
class tab1State extends State<tab1> {
@override
Widget build(BuildContext cntx) {
debugPrint('tab loaded'); //this gets called when Navigator.pushNamed called and when back button pressed
//some heave processing with http.get here...
//...
return new Center(
child: new RaisedButton(
onPressed: () {
Navigator.pushNamed(context, '/some_other_page');
},
child: new Text('Open new page'),
));
}
}
2 回答
在
build
中,您应该只是构建Widget树,而不是进行任何繁重的处理 . 您的tab1是一个StatefulWidget,因此它的状态应该保持当前状态(包括繁重处理的结果) . 它的build
应该只是呈现该状态的当前版本 .在tab1state中,覆盖
initState
以设置初始值,并可能启动一些异步函数以开始执行提取 - 一旦结果可用就调用setState
. 在build
中,渲染当前状态,记住它可能只是部分可用,因为繁重的工作在后台继续 . 因此,例如,测试值为null并且可能用进度指示器或空容器替换它们 .使用StreamBuilder和FutureBuilder可以使fetch / setState /(可能是部分)渲染更加优雅 .
由于您在 build 函数内构建 BottomNavigationBar ,因此将重建 every time state changes .
为避免这种情况,您可以在 initState() 方法中构建 BottomNavigationBar ,如下所示,