flutter学习之创建一个内嵌的navigation详解-kb88凯时官网登录

来自:网络
时间:2023-06-25
阅读:
目录

简介

我们在flutter中可以使用navigator.push或者navigator.pushnamed方法来向navigator中添加不同的页面,从而达到页面调整的目的。

一般情况下这样已经足够了,但是有时候我们有多个navigator的情况下,上面的使用方式就不够用了。比如我们有一个d88尊龙官网手机app主页面app的navigator,然后里面有一个匹配好友的功能,这个功能有多个页面,因为匹配好友功能的多个页面实际上是一个完整的流程,所以这些页面需要被放在一个子navigator中,并和主navigator区分开。

那么应该如何处理呢?

搭建主navigator

主navigator是我们app的一些主要界面,这里我们有三个界面,分别是主home界面,一个setting配置界面和好友匹配界面。

其中好友匹配界面包含了三个子界面,这三个子界面将会用到子路由。

先来看下主路由,主路由的情况跟普通的路由没啥区别,这里我们首先定义和home和setting匹配的两个widget:homepage和settingspage:

class homepage extends statelesswidget {
  const homepage({
    super.key,
  });
  @override
  widget build(buildcontext context) {
    return scaffold(
      appbar: _buildappbar(context),
      body: center(
        child: padding(
          padding: const edgeinsets.symmetric(horizontal: 24.0),
          child: column(
            mainaxissize: mainaxissize.min,
            children: const [
              sizedbox(
                width: 250,
                height: 250,
                child: center(
                  child: icon(
                    icons.home,
                    size: 175,
                    color: colors.blue,
                  ),
                ),
              ),
              sizedbox(height: 32),
              text(
                '跳转到好友匹配页面',
                textalign: textalign.center,
                style: textstyle(
                  fontsize: 24,
                  fontweight: fontweight.bold,
                ),
              ),
            ],
          ),
        ),
      ),
      floatingactionbutton: floatingactionbutton(
        onpressed: () {
          navigator.of(context).pushnamed(routefriendmatch);
        },
        child: const icon(icons.add),
      ),
    );
  }

homepage很简单,它包含了一个floatingactionbutton,当点击它的时候会调用 navigator.pushnamed方法进行路由切换。

然后是settingspage,它是一个简单的column:

class settingspage extends statelesswidget {
  const settingspage({
    super.key,
  });
  @override
  widget build(buildcontext context) {
    return scaffold(
      appbar: _buildappbar(),
      body: singlechildscrollview(
        child: column(
          mainaxissize: mainaxissize.min,
          children: list.generate(8, (index) {
            return  listtile(
              title: text('设置项$index'),
            );
          }),
        ),
      ),
    );
  }

最后一个页面是friendmatchflow,这个页面比较复杂,我们在下一个再进行讲解。

然后我们为主路由在ongenerateroute方法中进行定义:

void main() {
  runapp(
    materialapp(
      ongenerateroute: (settings) {
        late widget page;
        if (settings.name == routehome) {
          page = const homepage();
        } else if (settings.name == routesettings) {
          page = const settingspage();
        } else if (settings.name == routefriendmatch) {
          page = const friendmatchflow(
            setuppageroute: routefriendmatchpage,
          );
        }
        return materialpageroute(
          builder: (context) {
            return page;
          },
          settings: settings,
        );
      },
      debugshowcheckedmodebanner: false,
    ),
  );
}

主路由很简单,跟普通的路由没有太多的区别。

构建子路由

接下来是构建子路由的步骤。在主路由中,如果路由的名称是routefriendmatch,那么就会跳转到friendmatchflow。

而这个flow页面实际上是由几个子页面组成的:选择好友页面,等待页面,匹配页面和匹配完毕页面。

具体的页面代码这里就不写了,我们主要来讲一下子路由的使用。

对于friendmatchflow来说,它本身是一个navigator,所以我们的build方法是这样的:

  widget build(buildcontext context) {
    return willpopscope(
      onwillpop: _isexitdesired,
      child: scaffold(
        appbar: _buildflowappbar(),
        body: navigator(
          key: _navigatorkey,
          initialroute: widget.setuppageroute,
          ongenerateroute: _ongenerateroute,
        ),
      ),
    );
  }

因为他需要根据用户的不同点击来进行内部路由的切换,所以需要保存对当前子navigator的应用,所以这里friendmatchflow是一个statefulwidget,并且上面的_navigatorkey是一个globalkey对象,以提供对子navigator的引用:

  final _navigatorkey = globalkey();

这里的_ongenerateroute方法,跟主路由也是很类似的,主要定义的是子路由中页面的跳转:

  route _ongenerateroute(routesettings settings) {
    late widget page;
    switch (settings.name) {
      case routefriendmatchpage:
        page = waitingpage(
          message: '匹配附近的好友...',
          onwaitcomplete: _ondiscoverycomplete,
        );
        break;
      case routefriendselectpage:
        page = selectfriendpage(
          onfriendselected: _onfriendselected,
        );
        break;
      case routefriendconnectingpage:
        page = waitingpage(
          message: '匹配中...',
          onwaitcomplete: _onconnectionestablished,
        );
        break;
      case routefriendfinishedpage:
        page = finishedpage(
          onfinishpressed: _exitsetup,
        );
        break;
    }

这里的on***selected是voidcallback回调,用来进行路由的切换:

  void _ondiscoverycomplete() {
    _navigatorkey.currentstate!.pushnamed(routefriendselectpage);
  }
  void _onfriendselected(string deviceid) {
    _navigatorkey.currentstate!.pushnamed(routefriendconnectingpage);
  }
  void _onconnectionestablished() {
    _navigatorkey.currentstate!.pushnamed(routefriendfinishedpage);
  }

可以看到上面的路由切换实际上是在子路由上切换,跟父路由无关。

如果想要直接从子路由跳出到父路由该怎么处理呢?很简单,调用navigator.of的pop方法即可:

  void _exitsetup() {
    navigator.of(context).pop();
  }

这里的context默认是全局的context,所以会导致主路由的跳转变化。

总结

以上的代码运行结果如下:

虽然上面的例子看起来复杂,但是大家只要记住了不同的路由使用不同的navigator范围进行跳转就行了。

返回顶部
顶部
网站地图