带有抽屉的Flutter导航堆栈

时间:2019-06-20 19:55:02

标签: flutter

我正在使用Flutter构建多页应用程序,并且看来我对导航的处理不正确。我注意到,当我在屏幕之间导航时,似乎只是不断将页面推入我的堆栈,并且每次都“评估”整个堆栈。我在所有页面上都包含一个应用抽屉小部件,如下所示:

@override
  Widget build(BuildContext context) {
    AuthenticationContext authenticationContext =
      AuthenticationContext.of(context);
    auth = authenticationContext.auth;
    var drawerOptions = <Widget>[];
    for (var i = 0; i < drawerItems.length; i++) {
      var d = drawerItems[i];
      drawerOptions.add(new ListTile(
        leading: new Icon(d.icon),
        title: new Text(d.title),
        selected: i == _selectedDrawerIndex,
        onTap: () => _onSelectItem(i),
      ));
    }

    return new Drawer(
      child: new Column(
        children: <Widget>[
          UserAccountsDrawerHeader(
            accountName: Text(widget.name != null ? widget.name : ""),
            accountEmail: Text(widget.email),
            currentAccountPicture: CircleAvatar(
              child: new Text(
                  widget.photoUrl == null ? widget.email[0].toUpperCase() : ""),
            ),
          ),
          new Column(children: drawerOptions)
        ],
      ),
    );
  }

  _getDrawerItemWidget(int pos) {
    switch (pos) {
      case 0:
        return new HomePage();
      case 1:
        return new UserPantryPage();
      case 2:
        return new ShoppingListPage();
      case 3:
        return new FavoritesPage();
      case 4:
        auth.signOut();
        return new RootPage();
      default:
        return new Text("Error");
    }
  }

  _onSelectItem(int index) {
    Navigator.of(context).pop();
    Navigator.of(context)
        .push(MaterialPageRoute<Null>(builder: (BuildContext context) {
      return _getDrawerItemWidget(index);
    }));
  }

我在每个页面小部件中都有调试打印语句,如果我开始在抽屉上单击以在页面之间导航,我会注意到它会从例如HomePage开始打印调试语句,即使我正在导航到一个完全独立的页面。我最初注意到它是因为我的页面之一调用了一些API来获取其build方法中的数据,而我使用该应用程序的次数越多,该API的调用就越多。我将其归结为一个事实,即即使我要转到另一个页面,似乎所有页面Widget的构建方法都被调用了。在多页面导航方面,我在这里做错什么了吗?页面应用程序?

2 个答案:

答案 0 :(得分:0)

尝试以下伪代码。问题在于,可以在应用程序的生命周期中多次调用build方法,因此,为了避免多次执行代码,可以使用覆盖方法或以下示例将其移至仅调用一次的初始状态。 。更多信息在这里-https://flutterbyexample.com/stateful-widget-lifecycle/

class NavigationDraw extends StatefulWidget {
  NavigationDraw({Key key, this.email, this.name}) : super(key:key);
  final String email;
  final String name;
  @override
  _NavigationDrawState createState() =>
      new _NavigationDrawState();
}

class _NavigationDrawState extends State<NavigationDraw> {
  BuildContext _ctx;
  var navi;

_NavigationDrawState () {
    navi = sideNavi();
  }


@override
  Widget build(BuildContext context) {

    return navi;

  }

sideNavi(){
     _getDrawerItemWidget(int pos) {
        switch (pos) {
          case 0:
            return new HomePage();
          case 1:
            return new UserPantryPage();
          case 2:
            return new ShoppingListPage();
          case 3:
            return new FavoritesPage();
          case 4:
            auth.signOut();
            return new RootPage();
          default:
            return new Text("Error");
        }
      }

      _onSelectItem(int index) {
        Navigator.of(context).pop();
        Navigator.of(context)
            .push(MaterialPageRoute<Null>(builder: (BuildContext context) {
          return _getDrawerItemWidget(index);
        }));
      }
  AuthenticationContext authenticationContext = AuthenticationContext.of(context);
    auth = authenticationContext.auth;
    var drawerOptions = <Widget>[];

    for (var i = 0; i < drawerItems.length; i++) {
      var d = drawerItems[i];
      drawerOptions.add(
         new ListTile(
         leading: new Icon(d.icon),
         title: new Text(d.title),
         selected: i == _selectedDrawerIndex,
         onTap: () => _onSelectItem(i),
        ));
    }
   return new Drawer(
      child: new Column(
        children: <Widget>[
          UserAccountsDrawerHeader(
            accountName: Text(widget.name != null ? widget.name : ""),
            accountEmail: Text(widget.email),
            currentAccountPicture: CircleAvatar(
              child: new Text(
                  widget.photoUrl == null ? widget.email[0].toUpperCase() : ""),
            ),
          ),
          new Column(children: drawerOptions)
        ],
      ),
    );
}

答案 1 :(得分:0)

当您浏览时,Flutter会播放屏幕过渡的动画。因此,正在动画的小部件会不断重建,因为它们在动画过程中可能会在视觉上发生变化。使用默认的淡入淡出和幻灯片动画,您倾向于同时建立3个屏幕-旧的屏幕逐渐消失,新的屏幕逐渐消失,而旧屏幕下方的屏幕则由于其他两个部分被遮盖而略微可见消失时保持透明。

解决问题的方法(以及与Flutter共同使用的方法)是将与UI无关的所有内容移出build函数。如果您需要在初始化小部件时获取一些数据,请将代码移至initState的{​​{1}}函数中。