颤振的嵌套路线 [英] Nesting routes with flutter

查看:69
本文介绍了颤振的嵌套路线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解决以下问题的好的体系结构解决方案:我遵循的第一级路线也可以称为布局

I am trying to figure out good architectural solution for following problem: I have following First level routes that can also be referred to as layouts:

/onboarding/* -> Shows onboarding layout
/dashboard/* -> Shows dashboard layout
/overlay/* -> shows slide up overlay layout
/modal/* -> shows modal layout

根据用户的身份验证状态,操作等将用户路由到其中的每一个

User is routed to each of these depending on his/her auth state, actions etc.. I got this stage correctly.

当我想使用次要级别路由(称为页面,例如

Issues arise when I want to use Secondary level routes that can be referred to as pages, for example

/onboarding/signin -> Shows onboarding layout, that displays signin route
/onboarding/plan -> Shows onboarding layout, that displays plan options
/modal/plan-info -> Shows modal layout, over previous page (/onboarding/plan) and displays plan-information page.

如何最好地定义/组织这些方式,以便有效地路由至布局和页面显示?请注意,每当我在一种布局中路由页面时,布局都不会改变,但是我想根据路由来为其内部变化的内容(页面)设置动画。

How can I best define / organise these in a way where I can efficiently route to layouts and pages they display? Note, that whenever I route pages inside one layout, layout is not changing, but I want to animate content (pages) that are changing inside of it based on route.

到目前为止,我实现了以下

Thus far I achieved following

import "package:flutter/widgets.dart";
import "package:skimitar/layouts/Onboarding.dart";
import "package:skimitar/layouts/Dashboard.dart";

Route generate(RouteSettings settings) {
  Route page;
  switch (settings.name) {
    case "/onboarding":
      page = new PageRouteBuilder(pageBuilder: (BuildContext context,
          Animation<double> animation, Animation<double> secondaryAnimation) {
        return new Onboarding();
      });
      break;
      case "/dashboard":
      page = new PageRouteBuilder(pageBuilder: (BuildContext context,
          Animation<double> animation, Animation<double> secondaryAnimation) {
        return new Dashboard();
      });
      break;
  }
  return page;
}

/* Main */
void main() {
  runApp(new WidgetsApp(
      onGenerateRoute: generate, color: const Color(0xFFFFFFFFF)));
}

这将转到登机和仪表板布局(现在仅是用于包装文本的简单容器) )。我也相信我可以使用 PageRouteBuilder 来设置路线之间的过渡动​​画吗?现在,我需要弄清楚在登机和仪表板上如何放置嵌套的辅助路由器之类的东西。

This routes to on boarding and dashboard layouts (right now just simple Containers wrapping text). I also believe that I can use PageRouteBuilder latter on to animate transitions between routes? Now I need to figure out how to have something like nested secondary router inside on boarding and dashboard.

下面的内容有点像我要实现的目标是,我必须能够成功路由蓝色和红色位。在此示例中,只要我们位于 / dashboard 下,蓝色位(布局)就不会更改,但是当我们从 / dashboard / home导航时 / dashboard / stats 红色位(页面)应淡出并随新内容淡入。如果我们从 / dashboard / home 导航到说 / onboarding / home ,则红色部分(布局)应消失消失,以及其当前处于活动状态的页面并显示新的入职布局,故事继续进行。

Below is somewhat of a visual representation of what I want to achieve, I need to be able to successfully route blue and red bits. In this example as long as we are under /dashboard blue bit (layout) doesn't change, but as we navigate from say /dashboard/home to /dashboard/stats the red bit (page) should fade out and fade in with new content. If we navigate away from /dashboard/home to say /onboarding/home, the red bit (layout) should fade away, along with its currently active page and show new layout for onboarding and the story continues.

编辑我在下面概述的方法上取得了一些进展,基本上,我将确定 runApp ,并声明新的 WidgetsApp 并在每个布局内进行路由。看来可行,但是有一个问题,当我单击 SignUp时,我被重定向到正确的页面,但是我也可以看到它下面的旧页面。

EDIT I made a bit of the progress with approach outlined below, essentially I will determine layout inside my runApp and will declare new WidgetsApp and routes inside each of the layouts. It seems to work, but there is an issue, When I click "SignUp" I am redirected to correct page, but I can also see old page below it.

main.dart

import "package:flutter/widgets.dart";
import "package:myProject/containers/layouts/Onboarding.dart";

/* Main */
void main() {
  runApp(new Onboarding());
}

Onboarding.dart

import "package:flutter/widgets.dart";
import "package:myProject/containers/pages/SignIn.dart";
import "package:myProject/containers/pages/SignUp.dart";
import "package:myProject/services/helpers.dart";

/* Onboarding router */
Route onboardingRouter(RouteSettings settings) {
  Route page;
  switch (settings.name) {
    case "/":
      page = buildOnboardingRoute(new SignIn());
      break;
    case "/sign-up":
      page = buildOnboardingRoute(new SignUp());
      break;
    default:
      page = buildOnboardingRoute(new SignIn());
  }
  return page;
}

class Onboarding extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      decoration: new BoxDecoration(
          color: const Color(0xFF000000),
          image: new DecorationImage(
              image: new AssetImage("assets/images/background-fire.jpg"),
              fit: BoxFit.cover)),
      child: new WidgetsApp(
          onGenerateRoute: onboardingRouter, color: const Color(0xFF000000)),
    );
  }
}

SignUp.dart

import "package:flutter/widgets.dart";

class SignUp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
        child: new Text("Sign Up",
            style: new TextStyle(color: const Color(0xFFFFFFFF))));
  }
}

helpers.dart

import "package:flutter/widgets.dart";

Route buildOnboardingRoute(Widget page) {
  return new PageRouteBuilder(
      opaque: true,
      pageBuilder: (BuildContext context, _, __) {
        return page;
      });
}


推荐答案

虽然在技术上可以嵌套导航器,此处不建议使用(因为它会破坏 Hero 动画)

While it's technically possible to nest "Navigator", this is unrecommended here (as it breaks Hero animation)

您可以在onGenerateRoute上使用 来构建嵌套的 routes,在路线 / dashboard / profile的情况下,构建树 WidgetApp>仪表板>个人资料。我假设这是您要实现的目标。

You can use onGenerateRoute to build nested 'routes', in the case of a route '/dashboard/profile', build a Tree WidgetApp > Dashboard > Profile. Which I assume is what you're trying to achieve.

结合更高阶的函数,您可以创建在onGenerateRoute上创建的东西

Combined with a higher order function, you can have something that creates onGenerateRoute for you.

要提供代码流的线索: NestedRoute 忽略了确切的版式的构建,然后将其放入 builder 方法( eg builder:(child)=> new Dashboard( child:child),)。当调用 buildRoute 方法时,我们将为该页面的实例生成一个 PageRouteBuilder ,但让 _build 管理小部件的创建。在 _build 中,我们按原样使用 builder -或通过调用所请求的子路由,使该子路由膨胀,调用自己的 _build 。完成后,我们将使用构建的子路由作为构建器的参数。简而言之,您可以递归地钻入更多的路径层以构建路线的最后一层,然后让它从递归中上升,并将结果用作外部层的参数,依此类推。

To provide a clue of the code-flow: the NestedRoute neglects the exact build of the layout, letting it in the builder method (e.g. builder: (child) => new Dashboard(child: child),). When calling the buildRoute method we will generate a PageRouteBuilder for the very instance of this page, but letting _build manage the creation of the Widgets. In _build we either use the builder as is - or let it inflate the subroute, by recalling the requested subroute, calling its own _build. Once done, we'll be using the built subroute as the argument of our builder. Long story short, you recursively dive into further path levels to build the last level of the route, then let it rise from recursion and use the result as an argument for the outer level and so on.

BuildNestedRoutes 为您完成工作,并解析 NestedRoutes 的列表以构建必要的 RouteSettings

BuildNestedRoutes does the dirty job for you and parses the lists of NestedRoutes to build the necessary RouteSettings.

因此,从下面的示例中

示例:

@override
Widget build(BuildContext context) {
  return new MaterialApp(
    initialRoute: '/foo/bar',
    home: const FooBar(),
    onGenerateRoute: buildNestedRoutes(
      [
        new NestedRoute(
          name: 'foo',
          builder: (child) => new Center(child: child),
          subRoutes: [
            new NestedRoute(
              name: 'bar',
              builder: (_) => const Text('bar'),
            ),
            new NestedRoute(
              name: 'baz',
              builder: (_) => const Text('baz'),
            )
          ],
        ),
      ],
    ),
  );
}

在这里,您只需定义嵌套的路由(名称+相关组件)。
NestedRoute 类+ buildNestedRoutes 方法的定义方式是:

Here you simply defined your nested routes (name + associated component). And NestedRoute class + buildNestedRoutes method are defined this way :

typedef Widget NestedRouteBuilder(Widget child);

@immutable
class NestedRoute {
  final String name;
  final List<NestedRoute> subRoutes;
  final NestedRouteBuilder builder;

  const NestedRoute({@required this.name, this.subRoutes, @required this.builder});

  Route buildRoute(List<String> paths, int index) {
    return new PageRouteBuilder<dynamic>(
      pageBuilder: (_, __, ___) => _build(paths, index),
    );
  }

  Widget _build(List<String> paths, int index) {
    if (index > paths.length) {
      return builder(null);
    }
    final route = subRoutes?.firstWhere((route) => route.name == paths[index], orElse: () => null);
    return builder(route?._build(paths, index + 1));
  }
}

RouteFactory buildNestedRoutes(List<NestedRoute> routes) {
  return (RouteSettings settings) {
    final paths = settings.name.split('/');
    if (paths.length <= 1) {
      return null;
    }
    final rootRoute = routes.firstWhere((route) => route.name == paths[1]);
    return rootRoute.buildRoute(paths, 2);
  };
}

这样,您的 Foo Bar 组件不会与您的路由系统紧密耦合;但仍然有嵌套路线。
比起将您的路线分散到各地更容易理解。您将轻松添加一个新的。

This way, your Foo and Bar components will not be tightly coupled with your routing system ; but still have nested routes. It's more readable then having your routes dispatched all over the place. And you'll easily add a new one.

这篇关于颤振的嵌套路线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆