Routing 带颤振的嵌套路径
我正试图为以下问题找到良好的体系结构解决方案:我有以下一级路线,也可以称为布局: 根据用户的身份验证状态、操作等,用户将被路由到其中的每一个。。我正确地理解了这个阶段 例如,当我想使用可称为页面的二级路由时,会出现问题Routing 带颤振的嵌套路径,routing,dart,flutter,Routing,Dart,Flutter,我正试图为以下问题找到良好的体系结构解决方案:我有以下一级路线,也可以称为布局: 根据用户的身份验证状态、操作等,用户将被路由到其中的每一个。。我正确地理解了这个阶段 例如,当我想使用可称为页面的二级路由时,会出现问题 /onboarding/signin -> Shows onboarding layout, that displays signin route /onboarding/plan -> Shows onboarding layout, that displays p
/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.
我如何才能最好地定义/组织这些内容,以便有效地将其发送到布局和显示的页面?请注意,每当我在一个布局中路由页面时,布局不会改变,但我希望根据路由设置其内部正在改变的内容(页面)的动画
到目前为止,我取得了以下成就
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)));
}
入职。dart
import "package:flutter/widgets.dart";
import "package:myProject/containers/layouts/Onboarding.dart";
/* Main */
void main() {
runApp(new Onboarding());
}
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)),
);
}
}
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))));
}
}
import "package:flutter/widgets.dart";
Route buildOnboardingRoute(Widget page) {
return new PageRouteBuilder(
opaque: true,
pageBuilder: (BuildContext context, _, __) {
return page;
});
}
注册。省道
import "package:flutter/widgets.dart";
import "package:myProject/containers/layouts/Onboarding.dart";
/* Main */
void main() {
runApp(new Onboarding());
}
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)),
);
}
}
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))));
}
}
import "package:flutter/widgets.dart";
Route buildOnboardingRoute(Widget page) {
return new PageRouteBuilder(
opaque: true,
pageBuilder: (BuildContext context, _, __) {
return page;
});
}
助手。省道
import "package:flutter/widgets.dart";
import "package:myProject/containers/layouts/Onboarding.dart";
/* Main */
void main() {
runApp(new Onboarding());
}
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)),
);
}
}
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))));
}
}
import "package:flutter/widgets.dart";
Route buildOnboardingRoute(Widget page) {
return new PageRouteBuilder(
opaque: true,
pageBuilder: (BuildContext context, _, __) {
return page;
});
}
您试图构建的模式,即使是合理的,似乎也无法用flatter直接表示出来
编辑:您想要实现的行为需要使用onGenerateRoute,但尚未(2018年1月)正确记录()。请参见@Darky answer以获得示例。他提出了NestedRouteBuilder
和NestedRoute
实现,填补了这一空白
使用MaterialApp中的普通导航器,路由和页面导航(根据)有两个主要特征,它们否定了您想要实现的目标(至少是直接实现的)。一方面,Navigator
表现为一个堆栈,从而将一条路由推到下一条路由之上,以此类推,另一条路由要么是全屏路由,要么是模式路由,这意味着它们占据了部分屏幕,但它们抑制了与下方小部件的交互。更明确地说,您的范例似乎需要在堆栈中的不同的级别上与页面同时交互-这不能用这种方式完成
此外,它感觉路径范式不仅仅是一个层次-一般框架→ 特定子页面-但首先是导航器中堆栈的表示形式。我自己也被骗了,但我明白了:
String initialRoute
final
要显示的第一条管线的名称
默认情况下,这遵从dart:ui.Window.defaultRouteName
如果此字符串包含任何/个字符,则该字符串在
从字符串开始到结束的那些字符和子字符串
每一个这样的字符依次用作推送的路径
例如,如果使用route/stocks/HOOLI作为初始路由,
然后导航器将在启动时推送以下路由:/,
/股票,/股票/胡利。这将启用深度链接,同时允许
用于维护可预测路线历史记录的应用程序
一种可能的解决方法,如下所示,是利用路径名实例化子窗口小部件,保留一个状态变量以知道显示什么:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new ActionPage(title: 'Flutter Demo Home Page'),
routes: <String, WidgetBuilder>{
'/action/plus': (BuildContext context) => new ActionPage(sub: 'plus'),
'/action/minus': (BuildContext context) => new ActionPage(sub: 'minus'),
},
);
}
}
class ActionPage extends StatefulWidget {
ActionPage({Key key, this.title, this.sub = 'plus'}) : super(key: key);
final String title, sub;
int counter;
final Map<String, dynamic> subroutes = {
'plus': (BuildContext context, int count, dynamic setCount) =>
new PlusSubPage(count, setCount),
'minus': (BuildContext context, int count, dynamic setCount) =>
new MinusSubPage(count, setCount),
};
@override
ActionPageState createState() => new ActionPageState();
}
class ActionPageState extends State<ActionPage> {
int _main_counter = 0;
String subPageState;
@override
void initState() {
super.initState();
subPageState = widget.sub;
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Testing subpages'),
actions: <Widget>[
new FlatButton(
child: new Text('+1'),
onPressed: () {
if (subPageState != 'plus') {
setState(() => subPageState = 'plus');
setState(() => null);
}
}),
new FlatButton(
child: new Text('-1'),
onPressed: () {
if (subPageState != 'minus') {
setState(() => subPageState = 'minus');
setState(() => null);
}
}),
],
),
body: widget.subroutes[subPageState](context, _main_counter, (count) {
_main_counter = count;
}));
}
}
class PlusSubPage extends StatefulWidget {
PlusSubPage(this.counter, this.setCount);
final setCount;
final int counter;
@override
_PlusSubPageState createState() => new _PlusSubPageState();
}
class _PlusSubPageState extends State<PlusSubPage> {
int _counter = 0;
@override
void initState() {
super.initState();
_counter = widget.counter;
}
void _incrementCounter() {
setState(() {
_counter++;
widget.setCount(_counter);
});
}
@override
Widget build(BuildContext context) {
return new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new IconButton(
icon: const Icon(Icons.add),
onPressed: _incrementCounter,
),
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
);
}
}
class MinusSubPage extends StatefulWidget {
MinusSubPage(this.counter, this.setCount);
final setCount;
final int counter;
@override
_MinusSubPageState createState() => new _MinusSubPageState();
}
class _MinusSubPageState extends State<MinusSubPage> {
int _counter = 0;
@override
void initState() {
super.initState();
_counter = widget.counter;
}
void _decrementCounter() {
setState(() {
_counter--;
widget.setCount(_counter);
});
}
@override
Widget build(BuildContext context) {
return new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new IconButton(
icon: const Icon(Icons.remove),
onPressed: _decrementCounter,
),
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
);
}
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(新的MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回新材料PP(
标题:“颤振演示”,
主题:新主题数据(
主样本:颜色。蓝色,
),
主页:新的ActionPage(标题:“颤振演示主页”),
路线:{
“/action/plus”:(BuildContext上下文)=>newactionPage(sub:'plus'),
“/action/minus”:(BuildContext上下文)=>newactionPage(sub:'minus'),
},
);
}
}
类ActionPage扩展StatefulWidget{
ActionPage({Key-Key,this.title,this.sub='plus'}):super(Key:Key);
最终字符串标题,子字符串;
整数计数器;
最终映射子例程={
“plus”:(BuildContext上下文、int计数、动态setCount)=>
新PlusSubPage(计数,设置计数),
“减”:(BuildContext上下文、int计数、动态setCount)=>
新的子页面(计数,设置计数),
};
@凌驾
ActionPageState createState()=>新建ActionPageState();
}
类ActionPageState扩展了状态动画,它们可以为您提供在视图之间寻找的连续性。虽然从技术上讲可以嵌套“Navigator”,但这里不推荐这种做法(因为它破坏了英雄动画)
您可以使用onGenerateRoute
构建嵌套的“路由”,在路由“/dashboard/profile”的情况下,构建树WidgetApp>dashboard>profile
。我想这就是你想要实现的
结合一个高阶函数,您可以为自己创建onGenerateRoute
为了提供代码流的线索:NestedRoute
忽略了布局的精确构建,让它进入builder
方法(例如builder:(child)=>新仪表板(child:child),
)。调用buildRoute
方法时,我们将为此页面的实例生成一个PageRouteBuilder
,但是让\u build
管理小部件的创建。在\u build
中,我们要么按原样使用生成器
,要么让它调用请求的子例程,调用自己的\u build
来膨胀子例程。完成后,我们将使用构建的子例程作为构建器的参数。长话短说,您递归地深入到进一步的路径级别,以构建路由的最后一个级别,然后让它从递归中上升,并将结果用作外部级别的参数,依此类推
BuildNestedRoutes
为您执行脏工作,并解析NestedRoutes
列表,以构建必要的路由设置
下面的例子
例如:
@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
class+buildNestedRoutes
方法定义如下:
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);
};
}
typedef小部件NestedRouteBuilder(小部件子部件);
@不变的