14 . 跨组件共享数据
视图层级比较深的UI样式,直接通过属性传值会导致很多中间层增加冗余属性.
- 代码太多,见demo https://github.com/xfhy/FlutterBasic/tree/master/lib/data
14.1 InheritedWidget
- 共享父Widget的属性
14.2 Notification
- 从下往上的数据传递,在父Widget中监听来自子Widget的事件
14.3 EventBus
- EventBus 不依赖Widget树 这是事件总线,666
- 遵循发布订阅 模式
14.4 对比
方式 | 数据流动方式 | 使用场景 |
---|---|---|
属性传值 | 父到子 | 简单数据传递 |
InheritedWidget | 父到子 | 跨层数据传递 |
Notification | 子到父 | 状态通 |
EventBus | 发布订阅 | 消息批量同步 |
15 . 路由管理
- Route是页面的抽象,主要负责创建对应的界面,接收参数,响应Navigator打开和关闭
- Navigator则会维护一个路由栈管理Route,Route打开即入栈,Route关闭即出栈.
- 基本路由: 创建一个MaterialPageRoute实例,调用Navigator.push方法将新页面压到堆栈的顶部
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
//打开页面
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context) => SecondScreen()));
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
// 回退页面
onPressed: ()=> Navigator.pop(context)
);
}
}
- 命名路由: 简化路由管理,命名路由.给页面起一个名字,然后通过名字打开
MaterialApp(
...
//注册路由
routes:{
"second_page":(context)=>SecondPage(),
},
);
//使用名字打开页面
Navigator.pushNamed(context,"second_page");
- 错误路由处理,统一返回UnknownPage
MaterialApp(
...
//注册路由
routes:{
"second_page":(context)=>SecondPage(),
},
//错误路由处理,统一返回UnknownPage
onUnknownRoute: (RouteSettings setting) => MaterialPageRoute(builder: (context) => UnknownPage()),
);
//使用错误名字打开页面
Navigator.pushNamed(context,"unknown_page");
- 页面参数: Flutter提供了路由参数的机制,可以在打开路由时传递相关参数,在目标页面通过RouteSettings来获取页面参数
//打开页面时传递字符串参数
Navigator.of(context).pushNamed("second_page", arguments: "Hey");
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
//取出路由参数
String msg = ModalRoute.of(context).settings.arguments as String;
return Text(msg);
}
}
- 返回参数(类似startActivityForResult): 在push目标页面时,可以设置目标页面关闭时监听函数,以获取返回参数.而目标页面可以在关闭路由时传递相关参数.
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Text('Message from first screen: $msg'),
RaisedButton(
child: Text('back'),
//页面关闭时传递参数
onPressed: ()=> Navigator.pop(context,"Hi")
)
]
));
}
}
class _FirstPageState extends State<FirstPage> {
String _msg='';
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(children: <Widget>[
RaisedButton(
child: Text('命名路由(参数&回调)'),
//打开页面,并监听页面关闭时传递的参数
onPressed: ()=> Navigator.pushNamed(context, "third_page",arguments: "Hey").then((msg)=>setState(()=>_msg=msg)),
),
Text('Message from Second screen: $_msg'),
],),
);
}
}
- Navigator.push A->B->C->D,如何从 D页面 pop 到 B 呢?
Navigator.popUntil(context,ModalRoute.withName('B'));