调用Navigator.pushNamed时,bottomNavigationBar会多次重建

时间:2018-05-30 10:12:29

标签: dart flutter

我对Flutter项目的结构有疑问。

目前结构如下:

带有bottomNavigationBar的主页,其中包含多个选项卡,每个选项卡都是StatefulWidget,包含一些繁重的处理(远程API调用和数据显示)。

如果我从任何标签内部调用Navigator.pushNamed,则会发生以下情况:

  1. 所有选项卡都在后台重建(进行API调用等)。
  2. 新页面正常打开。
  3. 当我按下后退按钮时,页面关闭,所有标签再次重建。
  4. 总而言之,所有(每个标签)都重建了两次,只是为了打开外部导航页面。

    这是某种错误吗?完全不可理解为什么它在推出新路线之前完全重建bottomNavigationBar。

    它应该如何运作:

    1. 当我从选项卡内部调用Navigator.pushNamed时,应该打开新页面,并且不应重建所有bottomNavigationBar选项卡并保持不变状态。
    2. 当我按下时,页面应该关闭,用户返回到相同的bottomNavigationBar状态和它的标签,完全没有重建。
    3. 这可能实现吗?

      以下是代码:

      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 个答案:

答案 0 :(得分:0)

build中,你应该只是构建Widget树,进行任何繁重的处理。您的tab1是一个StatefulWidget,因此它的状态应该保持当前状态(包括繁重处理的结果)。它的build应该只是呈现该状态的当前版本。

在tab1state中,覆盖initState以设置初始值,并可能启动一些异步函数以开始进行提取 - 一旦结果可用就调用setState。在build中,渲染当前状态,记住它可能只是部分可用,因为繁重的工作在后台继续。因此,例如,测试值为null并且可能用进度指示器或空容器替换它们。

使用StreamBuilder和FutureBuilder可以使fetch / setState /(可能是部分)渲染更加优雅。

答案 1 :(得分:0)

由于您要在 BottomNavigationBar 功能中构建 build ,因此会重建 every time state changes

为避免这种情况,您可以在 BottomNavigationBar 方法中构建 initState() ,如下所示,

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {
  BottomNavigationBar _bottomNavigationBar;

  @override
  void initState() {
    super.initState();

    _bottomNavigationBar = _buildBottomNavigationBar();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new Center(child: new Text('Hello', style: new TextStyle(decoration: TextDecoration.underline),),),
      bottomNavigationBar: _bottomNavigationBar, // Use already created BottomNavigationBar rather than creating a new one
    );
  }

  // Create BottomNavigationBar
  BottomNavigationBar _buildBottomNavigationBar() {
    return new BottomNavigationBar(
      items: [
        new BottomNavigationBarItem(
            icon: new Icon(Icons.add),
            title: new Text("trends")
        ),
        new BottomNavigationBarItem(
            icon: new Icon(Icons.location_on),
            title: new Text("feed")
        ),
        new BottomNavigationBarItem(
            icon: new Icon(Icons.people),
            title: new Text("community")
        )
      ],
      onTap: (index) {},
    );
  }
}